トップ 最新 追記

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|

2014-03-02 [iOS]すれちがい通信(その6)

Core Bluetoothと使ったすれちがい通信だと、アプリケーションがバッググラウンドで動作している場合、通信の頻度が低くなるので、iBeaconを試してみる事にした。

自分で調べた訳ではないので間違っていたら申し訳ないが、iBeaconはBluetooth LEのAdvertisingパケットにiBeacon用の情報を埋め込んだもののようだ。つまり、サービスのスキャンで情報を受け取れるという事か?

まずは、バックグラウンドでもすれちがい通信できるようにInfo.plistを設定する。

Info.plist

iBeacon関連のフレームワークを使うとコードは簡素になる。Periperal側は以下のとおり。

@implementation BeaconPeripheralResponseParser
...
- (void)parse
{
    self.state = kBeaconPeripheralStateAdvertising;
    
    /* CBPeripheralManagerを生成 */
    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self
                                                                     queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
    if (! self.peripheralManager) {
        /* CBPeripheralManagerの初期化失敗 */
        self.state = kBeaconPeripheralStateError;
        self.error = [self _errorWithCode:kBeaconPeripheralResponseParserGenericError
                     localizedDescription:@"CBPeripheralManagerの初期化に失敗しました。"];
        return;
    }
    
    /* ビーコン領域を生成 */
    NSUUID  *uuid = [[NSUUID alloc] initWithUUIDString:BEACON_SERVICE_UUID];
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
                                                                major:12345
                                                                minor:67890
                                                           identifier:@"demo.Wibree.BeaconCentralResponseParser"];
    if (! self.beaconRegion) {
        /* ビーコン領域の初期化失敗 */
        self.state = kBeaconPeripheralStateError;
        self.error = [self _errorWithCode:kBeaconPeripheralResponseParserGenericError
                     localizedDescription:@"ビーコン領域の初期化に失敗しました。"];
        self.peripheralManager = nil;
        return;
    }
    
    /* 告知開始 */
    NSDictionary    *dictionary = [self.beaconRegion peripheralDataWithMeasuredPower:nil];
    [self.peripheralManager startAdvertising:dictionary];
}
...
@end

Central側はこうなる。

@implementation BeaconCentralResponseParser
...
- (void)parse
{
    self.state = kBeaconCentralStateScanning;
    
    /* CLLocationManagerを生成 */
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    if (! self.locationManager) {
        /* CLLocationManagerの初期化失敗 */
        self.state = kBeaconCentralStateError;
        self.error = [self _errorWithCode:kBeaconCentralResponseParserGenericError
                     localizedDescription:@"CLLocationManagerの初期化に失敗しました。"];
        return;
    }
    
    /* ビーコン領域を生成 */
    NSUUID  *uuid = [[NSUUID alloc] initWithUUIDString:BEACON_SERVICE_UUID];
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:@"demo.Wibree.BeaconCentralResponseParser"];
    if (! self.beaconRegion) {
        /* ビーコン領域の初期化失敗 */
        self.state = kBeaconCentralStateError;
        self.error = [self _errorWithCode:kBeaconCentralResponseParserGenericError
                     localizedDescription:@"ビーコン領域の初期化に失敗しました。"];
        self.locationManager = nil;
        return;
    }
    
    /* ビーコン領域の出入りを監視 */
    [self.locationManager startMonitoringForRegion:self.beaconRegion];
    
    /* 距離を監視 */
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}
...
@end

ビーコンが見つかるとCLLocationManagerDelegateのデリゲート・メソッドが呼ばれるので、それを実装する事になる。

@implementation BeaconCentralResponseParser
...
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    if ([self.delegate respondsToSelector:@selector(beaconCentralResponseParser:didEnterRegion:)]) {
        [self.delegate beaconCentralResponseParser:self didEnterRegion:region];
    }
}
 
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    if ([self.delegate respondsToSelector:@selector(beaconCentralResponseParser:didExitRegion:)]) {
        [self.delegate beaconCentralResponseParser:self didExitRegion:region];
    }
}
 
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
    if ([self.delegate respondsToSelector:@selector(beaconCentralResponseParser:didRangeBeacons:inRegion:)]) {
        [self.delegate beaconCentralResponseParser:self didRangeBeacons:beacons inRegion:region];
    }
}
...
@end

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/Wibree - GitHub

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)

2014-03-09 [iOS]すれちがい通信(その7)

iBeaconでの通信が成功したというのは間違いだった。申し訳ない。

CLLocationManagerDelegateの-locationManager:didRangeBeacons:inRegion:は検出できなくても周期的に呼ばれるようで、それで検出できたと考えたが、見つけたビーコン配列は空だった。そればかりが、動いていたCore Bluetoothの通信もできなくなっている!

結論をいうとInfo.plistのBackgraound Modesの「Location updates」と「Uses Bluetooth LE accessories」、「Acts as a Bluetooth LE accessory」を一緒に設定するとBluetooth LE通信ができなくなるようだ。

Info.plist

この設定をしなくすると動作するようになった。Core BluetoothとiBeaconの両方を使ってiOS機器同士で通信する場合は、注意が必要なようだ。

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/Wibree - GitHub

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)

トップ 最新 追記