<iOS>CoreBlueToothの実際の注意点、アイデア

こんにちは、Photosynth エンジニア@taku33です。
主にスマホ開発をやっております。

今回は、CoreBlueTooth API での、各処理で実装する際の注意点やアイデアを書きます。
ネットから見つけにくいけれど実際の実装では有益な情報を書きます。

タイムアウト

ViewControllerなどから各BLE処理を呼ぶ際は、NSTimerで事前にアプリ側上でのタイムアウト時間を設定しておきます。
これは、何らかの理由(途中で接続が切れた、有効距離外など)でBLE応答が来なかった場合、永遠に応答を待ち続けるのを防止するためです。
CoreBlueToothペリフェラルAPIの場合、タイムアウト時はアドバタイズを止めてwriteリクエストなどが来ないようにしておくといいと思います。

実際のタイムアウト時間ですが、セントラル機器側にもタイムアウト時間が定義されている場合は、それより多めにタイムアウト時間を取った方が良いかもしれません。全体の設計次第で上手く判断してください。

アドバタイズ

小技1

CoreBlueToothペリフェラルAPIにてアドバタイズを開始する際に、
CBAdvertisementDataLocalNameKeyというプロパティで自分が誰かをセントラル機器に伝えることができます。

しかし、もしセントラル機器がペリフェラルiOSに対してreadリクエストが出来ない場合、ペリフェラルiOS側が通信したいセントラル機器を限定するにはどうすればよいでしょうか。

先ほどのCBAdvertisementDataLocalNameKeyというプロパティには、通信したい特定のセントラル機器のMacアドレスなどを代わりに乗せて伝えることもできます。
これによりセントラル機器は自分のMacアドレスと一致した場合だけペリフェラルiOSと通信を続ける、といったワークアラウンドを取ることができます。

小技2

別の小技として、ペリフェラル機器(iOS以外)側でManufacturer Specific Dataにデータを乗せれば、セントラルiOS側はアドバタイズスキャンだけでフラグ情報などを見ることも可能です。
わざわざコネクトしなくても簡単な情報は見れるわけです。実際の実装においては、これで十分足りる場合もあるかと思います。
http://stackoverflow.com/questions/22833198/get-advertisement-data-for-ble-in-ios
また、この際にセントラルiOS側が継続してアドバタイズスキャンをすることも可能です。
http://stackoverflow.com/questions/9911102/core-bluetooth-constant-rssi-updates-of-in-range-devices


コネクト/ディスコネクト

CoreBlueToothセントラルAPIでは、コネクト/ディスコネクトが任意で操作できます。
しかしCoreBlueToothペリフェラルAPIでは、セントラル機器とのコネクト/ディスコネクトなどの状態変化すら通知されないため、アプリ側からみるといきなりデータ通信がはじまるようにみえます。

MTU

大量のデータをwirte/notifyする場合などは、
BluetoothSIGの仕様により一回の通信でやりとりできるデータのサイズ(MTU)は20バイほどが基本単位 になっているため、これを考慮する必要があります。
と言っても、実はiOS8,iOS9あたりはMTUが155バイト(+3バイトはオーバーヘッド)です。
これはつまり、iOSが155バイト位まではバッファにより1回で送ってくれるということなので、155バイト未満のペーロードで済むのならわざわざ20バイトを複数回に分けて送る必要はないです。
http://stackoverflow.com/questions/26623286/amount-of-data-to-be-sent-to-peripheral-using-bluetooth-in-ios-8