[iOS 7] [iBeacon] Mac を Beacon 端末にする

393件のシェア(そこそこ話題の記事)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

2014/11/06 更新
CBPeripheralManager が Yosemite (OS X 10.10) では動かないバグがあるようです。
そのため Mac で試す場合、Mavericks 以前の OS X バージョンで実行する必要があります。
http://stackoverflow.com/questions/25492316/cbperipheralmanager-startadvertising-not-working-on-os-x-yosemite
現在既にバグレポートが報告されているようなので、
次のバージョンでFixされることを期待するしかないようです。

情報を提供くださいました ppia さん、誠にありがとうございます!

2014/11/19 更新
Yosemite (OS X 10.10) で CBPeripheralManager を動作させたい場合、
Bluetooth の USB ドングルを利用すると良いようです。
http://stackoverflow.com/questions/25492316/cbperipheralmanager-startadvertising-not-working-on-os-x-yosemite
http://www.planex.co.jp/products/bt-micro4/

情報を提供くださいました Yuuki NISHIYAMA さん、誠にありがとうございます!

Mac を Beacon にしたい!

iBeacon Advent Calendar 2013 の19日目を担当します!

最近何かと話題の iBeacon。先日、弊社で開催した iBeacon 勉強会も満席・大盛況でした。足を運んでいただいたかた、Ust を御覧頂いたかた、誠にありがとうございましたm(_ _)m

会場風景

【iOS勉強会】iBeaconでできること – Developers.IO Meetup 02 を開催しました #cmdevio | Developers.IO

そんな iBeacon ですが、アプリを実装しテストするためには iOS 7 の端末(セントラル側)Beacon となる端末(ペリフェラル側)が必要です。会社でやるならまだしも、個人で開発する場合 iPhone を使っているなら1台は用意できたとしても、更にもう1台用意するのは大変かも知れません。。

そんなときはいまお使いの Mac を Beacon 端末にしましょう。ということで本記事では Beacon になる Mac アプリの作りかたを解説します!といっても似通った記事は多く出回っているので、Mac アプリの作り始めから順を追って解説してみたいと思います。下記の記事も参考になるので、こちらも併せてお読みください。

Mac アプリを作ってみる

まず Xcode を起動して新規プロジェクトを作りましょう。種類は OSX の CocoaApplication を選びます。

mac_beacon01

ProductName とか色々適当に作ります。iOS アプリを作る場合と同じ感じですね。

mac_beacon02

プロジェクトができたので、試しに起動してみましょう。

mac_beacon03

スッカラカンのアプリが起動しました。とりあえずアプリの起動は確認できたということで。

mac_beacon04

次に Bluetooth を使うために IOBluetooth.framework を追加します。iOS では CoreBluetooth.framework を使いますが、Mac の場合は IOBluetooth.framework を使います。

次にアドバタイズ用のデータを格納するクラスを作ります。iOS では CLBeaconRegion クラスがありますが、同様のクラスはないので作らなければいけません。

MBCBeaconAdvertisementData.h

#import <Foundation/Foundation.h>

@interface MBCBeaconAdvertisementData : NSObject

@property (strong,nonatomic) NSUUID *proximityUUID;
@property (assign,nonatomic) uint16_t major;
@property (assign,nonatomic) uint16_t minor;
@property (assign,nonatomic) int8_t measuredPower;

- (id)initWithProximityUUID:(NSUUID *)proximityUUID
                      major:(uint16_t)major
                      minor:(uint16_t)minor
              measuredPower:(int8_t)power;


- (NSDictionary *)beaconAdvertisement;

@end

MBCBeaconAdvertisementData.m

#import "MBCBeaconAdvertisementData.h"

@implementation MBCBeaconAdvertisementData

- (id)initWithProximityUUID:(NSUUID *)proximityUUID
                      major:(uint16_t)major
                      minor:(uint16_t)minor
              measuredPower:(int8_t)power {
    self = [super init];
    
    if (self) {
        _proximityUUID = proximityUUID;
        _major = major;
        _minor = minor;
        _measuredPower = power;
    }
    
    return self;
}


- (NSDictionary *)beaconAdvertisement {
    NSString *beaconKey = @"kCBAdvDataAppleBeaconKey";
    
    unsigned char advertisementBytes[21] = {0};
    
    [self.proximityUUID getUUIDBytes:(unsigned char *)&advertisementBytes];
    
    advertisementBytes[16] = (unsigned char)(self.major >> 8);
    advertisementBytes[17] = (unsigned char)(self.major & 255);
    
    advertisementBytes[18] = (unsigned char)(self.minor >> 8);
    advertisementBytes[19] = (unsigned char)(self.minor & 255);
    
    advertisementBytes[20] = self.measuredPower;
    
    NSMutableData *advertisement = [NSMutableData dataWithBytes:advertisementBytes length:21];
    
    return [NSDictionary dictionaryWithObject:advertisement forKey:beaconKey];
}

あとは AppDelegate にペリフェラルになる処理をコーディングしていきます。

MBCAppDelegate.h

#import <Cocoa/Cocoa.h>
#import <IOBluetooth/IOBluetooth.h>

#import "MBCBeaconAdvertisementData.h"

@interface MBCAppDelegate : NSObject <NSApplicationDelegate, CBPeripheralManagerDelegate>

@property (assign) IBOutlet NSWindow *window;
@property (strong, nonatomic) CBPeripheralManager *manager;

@end

MBCAppDelegate.m

#import "MBCAppDelegate.h"

@implementation MBCAppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // CBPeripheralManagerを初期化
    self.manager = [[CBPeripheralManager alloc] initWithDelegate:self
                                                           queue:nil];
}


- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
    // Bluetoothがオンのときにアドバタイズする
    if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
        
        // UUIDを適当に作成(uuidgenコマンドで生成する)
        NSUUID *proximityUUID = [[NSUUID alloc] initWithUUIDString:@"1E21BCE0-7655-4647-B492-A3F8DE2F9A02"];
        
        // アドバタイズ用のデータを作成
        MBCBeaconAdvertisementData *beaconData
            = [[MBCBeaconAdvertisementData alloc] initWithProximityUUID:proximityUUID
                                                                  major:1
                                                                  minor:1
                                                          measuredPower:-58];
        
        // アドバタイズ開始
        [peripheral startAdvertising:beaconData.beaconAdvertisement];
    }
}

@end

以上で実装完了です!アプリを起動すると iOS 7 の iBeacon アプリで検知できる Beacon になります。iBeacon アプリのほうは先日の勉強会で共有したアプリで試してみるといい感じに検知すると思います(もちろん、UUIDは合わせましょう!)。

mac_beacon05

まとめ

こんな感じで iOS 7 の端末が一台しかなくても iBeacon で遊ぶことができます。たくさんの Beacon 端末が必要な場合も、Mac も併用するとさらに多くの Beacon を作ることができますね!