update.BLEにおいて、1回の通信で送れるデータ量について調べた話です。はじめにまずはBLEの仕様を確認してみます。SpecificationのATT_MTUあたりを読むと、1回の通信で送れるデータ量は、デフォルトでは23octetsとなっています。Unitの略で、パケットの最大サイズと思っていいでしょう。実際には、3octetsは占有されているため、ユーザデータで使える容量は20octetsとなります。20octetsとなると、少量のデータしか送れず、場合によっては厳しい制限となるかもしれません。20octetsよりも大量のデータを送る場合、BLEには、2つの手段が用意されています。送信側で送信データをMTUに収まるサイズに分割し、ちょっとずつ送信する。Request)実際には、1と2の合わせ技で実装することもあるとは思いますが、この記事では、2のMTU拡張の方に焦点を絞っていきます。Requestとはサーバ・クライアント間で取り扱う単一のパケットの最大サイズ(ATT_MTU)を変更します。リクエストはクライアントサイド(Central)からサーバサイド(Peripheral)へします。ATT_MTUの規格上の最大サイズは512octetsですが、機器が対応しているとは限りません。サーバのMTUとクライアントのMTUが異なる場合は、低い方の値が両者に設定されます。サーバとクライアントで設定されるMTUが異なることはありません。Requestを実装し、設定できるMTUの最大値を確認します。1octet=1byteとします。Androidですが、公式リファレンスのBluetoothGattクラスを見ると、requestMtuメソッドがあるので、どうやら実装できそうです。MTUをサポートすると書かれています。CoreBluetoothのリファレンスを見ても、それらしいメソッドは見つかりませんでした。CBCentralクラスにread-onlyなmaximumUpdateValueLengthプロパティがあるくらいです。うーん、どうやってやるんだろう?検証ケース以下の4つのケースで検証します。Android(Peripheral)検証で使用した端末は以下の通りです。5.0.1ソースコードiOS、Androidのコードの一部抜粋をそれぞれ記載します。MTUの値を確認したいだけなので、文字列データをReadするだけの単純なコードです。iOSは、Peripheral側で取得できるCBPeripheralオブジェクトのmaximumUpdateValueLengthプロパティで確認します。ちなみに、このプロパティが返す値はユーザデータとして使える容量です。Androidは、CentralからrequestMtuメソッドを実行後に呼ばれるonMtuChangedコールバックメソッドで確認します。iOS(Peripheral)MTUは135B。iOS(Peripheral)AndroidでMTU拡張リクエストをしない場合、MTUは23B。AndroidでMTU拡張リクエストをした場合、MTUは158Bまで拡張できました。beta7をPeripheralにして試してみました。MTUは512Bまで拡張できました。Android(Peripheral)MTUは135B。Androidからは特にMTU拡張リクエストをしていませんが、onMtuChangedコールバックメソッドが呼ばれました。beta7をCentralで試したところ、185Bまで拡張されました。iOS10が正式リリースされたら、他の端末でも確認したいと思います。Android(Peripheral)MTU拡張リクエストをした場合、MTUは512Bまで拡張できました。これらの結果を考察すると以下のことが言えそうです。i0S10は185Bまで拡張をリクエストしているのではないかOSバージョンや端末によっては上限が異なる可能性はあるもう少し色々な端末で試してみたいところですが、今回の検証結果はこんな感じです。5.0.1)は、ペリフェラル端末としては利用できませんでした。supportedこんなエラーログが出てしまいました。iOS10からは、Peripheralで利用する場合、Info.plistにNSBluetoothPeripheralUsageDescriptionキーを指定し、何のために使うのかを説明しなければいけないようです。指定しないと、以下のようなログが出て、アプリはクラッシュしてしまいます。upLoginユーザーは見つかりませんでした。