以前書いた記事『iBeacon と BLE』に関係して、追加調査したことのメモ。
「iOSデバイスをiBeaconのビーコン側として使う」場合に、できること、できないことを確認したくて、いろいろためしてみました。
iOSデバイスをビーコンにしたときのアドバタイズの挙動
まず、(iBeacon的には)正規の方法でアドバタイズメントパケットを生成・アドバタイズする。
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
identifier:kIdentifier];
NSMutableDictionary *peripheralData = [beaconRegion peripheralDataWithMeasuredPower:nil];
[self.peripheralManager startAdvertising:peripheralData];
この実装をしたアプリを動かして Bluetooth Explorer でアドバタイズメントパケットの中身を確認してみると、iOS標準のManufacturer data と、iBeacon フォーマットの Manufacturer data とが一定時間間隔で交代で配信されている、ということがわかった。
普通の Manufacturer data の配信 n 回に対して iBeacon の Manufacturere data が1回、ぐらい。(Packet Logger で見るとよりハッキリわかる)
CBAdvertisementDataManufacturerDataKey を直接設定することはできない
iBeaconのアドバタイズメント・パケットのフォーマットがわかると、じゃあ CBAdvertisementDataManufacturerDataKey
に直接していすればいいじゃん、ということで
NSMutableDictionary *advertisementData = @{CBAdvertisementDataManufacturerDataKey: manufacturerData}.mutableCopy;
みたいにやってみたが、エラーにはならないものの、CBAdvertisementDataManufacturerDataKey
に渡した値はアドバタイズされなかった(Bluetooth Explorer で確認)。
iOSの普通の CBAdvertisementDataManufacturerDataKey
の値だけアドバタイズされる。
CLBeaconRegionの peripheralDataWithMeasuredPower:
で生成されるもの
NSMutableDictionary *peripheralData = [beaconRegion peripheralDataWithMeasuredPower:nil];
で生成したものをログ出力してみると、
peripheralData:{
kCBAdvDataAppleBeaconKey = <aab8f982 70304cff a5e902ab b8e6fef9 00000000 c8>;
kCBAdvDataLocalName = TestBeacon;
}
となる。
CBAdvertisementDataManufacturerDataKey
をログ出力すると "kCBAdvDataManufacturerData" だが、CLBeaconRegion の peripheralDataWithMeasuredPower:
で生成した場合、キーが "kCBAdvDataAppleBeaconKey" になる、ということがわかる。
あと、このとき、iBeaconフォーマットのうちcompany codeにあたる「4C00」は値から省略されている。
startAdvertising:
に渡す時点では辞書のキーに "kCBAdvDataManufacturerData" ではなく "kCBAdvDataAppleBeaconKey" を使うことで、最終的に iOS が manufacturer data として一定時間ごとに配信してくれる、というものらしい。
バックグラウンドでの挙動
perpheralのバックグラウンド実行モードを指定しても、バックグラウンドにまわると iBeacon フォーマットの一定時間ごとの Manufacturer Data の配信が止まる(普通の Manufacturer Data だけが配信される)。
ためしに Location のバックグラウンド実行モードをセットしてみてもだめだった。
というわけでiOSデバイスをビーコン側としてバックグラウンドで動かすことはできないっぽい。
たぶん "kCBAdvDataAppleBeaconKey" の値はバックグラウンドでは配信しないよ、という処理をiOSがアドバタイズメントパケットを決める際にやっているっぽい。
おわりに
そもそも、「iBeaconというBLEのサブセット仕様」の特長は
- 安い
- 省電力(ほとんど何もしない)
なので、iPhoneとかの高級・ハイスペック端末をビーコンにすること自体が筋がよろしくないのですが、なんでこんなことを調べてたかというと、Core Bluetooth のバックグラウンドでの挙動にはいろいろと制約があって、たとえばバックグラウンドにいるセントラルのiOSデバイスから、バックグラウンドにいるペリフェラルのiOSデバイスを検出できないのです。いろんな制約の兼ね合いで。
で、うまくiBeaconと併用してどうにかならないかなーと調査してみたのですが、結果、前述のとおり、iOSデバイスをビーコン側としてバックグラウンドで動かすことはできないという結論に至ったのでした。。