Upgrade to Pro — share decks privately, control downloads, hide ads and more …

つらくない(?) Bluetooth Low Energy on Android / TSURAI BLE on Android

9eed44f137609e6ce3b6f1e14f80b9e1?s=47 Masayuki Izumi
September 07, 2015

つらくない(?) Bluetooth Low Energy on Android / TSURAI BLE on Android

9eed44f137609e6ce3b6f1e14f80b9e1?s=128

Masayuki Izumi

September 07, 2015
Tweet

Transcript

  1. つらくない(?) Bluetooth Low Energy Masayuki IZUMI @izumin5210 Masayuki IZUMI @izumin5210

  2.  Rekimoto Lab. at the University of Tokyo (2008-2015: Akashi-NCT)

     Enginner at Wantedly, Inc. (2014.9-2015.2: Dmetlabel, Inc.)
  3. Ruby JavaScript Android Design pry(main) > izumin.skill_ratio

  4. Bluetooth Low Energy

  5. Android 4.3 (API Level 18) introduces built-in platform support for

    Bluetooth Low Energy in the central role and provides APIs that apps can use to discover devices, query for services, and read/write characteristics. - Bluetooth Low Energy | Android Developers
  6. Q. BLE つらくないですか

  7. Q. BLE つらくないですか A. つらいです

  8. BluetoothGatt Bluetooth LE の周辺機器は、サーバとして、センサの値、動作設定 値、内部状態などを公開しています。Bluetooth LE は、ある機能を サービスという単位にまとめます。1 つのサービスは複数のキャラ クタリスティクスを持ちます。例えばエアコンであれば、室内温度

    というサービスを作り、そのなかに気温センサの値というキャラク タリスティクスをもたせる設計をしたりします。 - BLE の通信仕様 - Reinforce-Lab.'s Blog* * http://reinforce-lab.github.io/blog/2013/08/13/blebook-ch2-ble-spec/
  9. BluetootGatt  GATT (Generic Attribute Profile)

  10. BluetootGatt  GATT (Generic Attribute Profile)  あらゆる BLE 端末は

    GATT に基いて データの送受信を行う
  11. BluetootGatt  GATT (Generic Attribute Profile)  あらゆる BLE 端末は

    GATT に基いて データの送受信を行う  Android では BluetoothGatt クラスを利用する
  12. BluetootGatt  GATT (Generic Attribute Profile)  あらゆる BLE 端末は

    GATT に基いて データの送受信を行う  Android では BluetoothGatt クラスを利用する ↑ こいつが闇
  13. BLE つらい問題 ちょっと触ってみた結果、どうにも悲しいことに 「1. 安定性がイケてない」 「2. SDK サンプルがイケてない」 「3. API

    仕様がイケてない」 という三重苦です。 - Android の BLE で Characteristics の Read/Write サンプルを作ってみた - ReDo** ** http://greety.sakura.ne.jp/redo/2013/11/androidblecharacteristicsreadwrite.html
  14. ここから,このつらい BLE まわりを なんとかマシに出来ないか試行錯誤していきます 

  15. BLE つらい問題 ちょっと触ってみた結果、どうにも悲しいことに 「1. 安定性がイケてない」 「2. SDK サンプルがイケてない」 「3. API

    仕様がイケてない」 という三重苦です。 - Android の BLE で Characteristics の Read/Write サンプルを作ってみた - ReDo** ** http://greety.sakura.ne.jp/redo/2013/11/androidblecharacteristicsreadwrite.html
  16. どうしようもねえ!!!

  17. イケてない API  すべての操作は非同期・コールバックベース

  18. BluetoothGattCallback onConnectionStateChange(BluetoothGatt gatt, int status, int newState) onServicesDiscovered(BluetoothGatt gatt, int

    status) onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
  19. BluetoothGattCallback onConnectionStateChange(BluetoothGatt gatt, int status, int newState) onServicesDiscovered(BluetoothGatt gatt, int

    status) onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
  20. BluetoothGattCallback  接続処理 BluetoothDevice#connectGatt() → onConnectionStateChange()

  21. BluetoothGattCallback  接続処理 BluetoothDevice#connectGatt() → onConnectionStateChange()  Service 探し BluetoothGatt#discoverService()

    → onServiceDiscovered()
  22. BluetoothGattCallback  接続処理 BluetoothDevice#connectGatt() → onConnectionStateChange()  Service 探し BluetoothGatt#discoverService()

    → onServiceDiscovered()  書き込み BluetoothGatt#writeCharacteristic() → onCharacteristicWrite()
  23. BluetoothGattCallback  接続処理 BluetoothDevice#connectGatt() → onConnectionStateChange()  Service 探し BluetoothGatt#discoverService()

    → onServiceDiscovered()  書き込み BluetoothGatt#writeCharacteristic() → onCharacteristicWrite()  切断処理 BluetoothGatt#disconnect() → onConnectionStateChange()
  24. BluetoothGattCallback  接続処理 BluetoothDevice#connectGatt() → onConnectionStateChange()  Service 探し BluetoothGatt#discoverService()

    → onServiceDiscovered()  書き込み BluetoothGatt#writeCharacteristic() → onCharacteristicWrite()  切断処理 BluetoothGatt#disconnect() → onConnectionStateChange()
  25. BluetoothGattCallback  接続処理 BluetoothDevice#connectGatt() → onConnectionStateChange()  Service 探し BluetoothGatt#discoverService()

    → onServiceDiscovered()  書き込み BluetoothGatt#writeCharacteristic() → onCharacteristicWrite()  切断処理 BluetoothGatt#disconnect() → onConnectionStateChange() ↓ 切断は disconnect() して, callback を待ってから close()
  26. イケてない API  すべての操作は非同期・コールバックベース  登録できる Callback インスタンスは 1 つ

  27. イケてない API  すべての操作は非同期・コールバックベース  登録できる Callback インスタンスは 1 つ

     ドキュメントにない仕様(disconnect → close とか)
  28. 対策①: 状態を意識する private static final int STATE_DISCONNECTED = 0; private

    static final int STATE_CONNECTING = 1; private static final int STATE_CONNECTED = 2; 公式サンプル
  29. 対策①: 状態を意識する private static final int STATE_DISCONNECTED = 0; private

    static final int STATE_CONNECTING = 1; private static final int STATE_CONNECTED = 2; 公式サンプル たりない
  30. 対策①: 状態を意識する enum State { DISCONNECTED, CONNECTING, CONNECTED, SERVICE_DISCOVERING, SERVICE_DISCOVERED,

    DISCONNECTING }
  31. 対策①: 状態を意識する enum State { DISCONNECTED, CONNECTING, CONNECTED, SERVICE_DISCOVERING, SERVICE_DISCOVERED,

    DISCONNECTING } ※ READING / WRITING 等も必要かもしれない
  32. 対策②: Callback のハンドリング  どの操作のコールバックかを判断するには, 引数に入ってるインスタンス見るしかない  普通にやると Callback Hell

    不可避
  33. 対策②: e.g. Enum でハンドリング @Override public onCharacteristicWrite() { CharacteristicHandler.valueOf(characteristic.getUuid()) .handle(characteristic);

    } enum CharacteristicHandler { DIGITAL_WRITE(/* ... */), DIGITAL_READ(/* ... */) UNKNOWN(null); public static CharacteristicHandler valueOf(UUID uuid) { /* ... */ } public UUID getUUID() { /* ... */ } public void handle() { /* ... */ } }
  34. 対策②: e.g. Enum でハンドリング @Override public onCharacteristicWrite() { CharacteristicHandler.valueOf(characteristic.getUuid()) .handle(characteristic);

    } enum CharacteristicHandler { DIGITAL_WRITE(/* ... */), DIGITAL_READ(/* ... */) UNKNOWN(null); public static CharacteristicHandler valueOf(UUID uuid) { /* ... */ } public UUID getUUID() { /* ... */ } public void handle() { /* ... */ } }
  35. 対策②: e.g. Enum でハンドリング @Override public onCharacteristicWrite(/* ... */) {

    CharacteristicHandler.valueOf(characteristic.getUuid()) .handle(characteristic); } enum CharacteristicHandler { DIGITAL_WRITE(/* ... */), DIGITAL_READ(/* ... */) UNKNOWN(null); public static CharacteristicHandler valueOf(UUID uuid) { /* ... */ } public UUID getUUID() { /* ... */ } public void handle() { /* ... */ } }
  36. 対策②: e.g. Enum でハンドリング @Override public onCharacteristicWrite(/* ... */) {

    CharacteristicHandler.valueOf(characteristic.getUuid()) .handle(characteristic); } enum CharacteristicHandler { DIGITAL_WRITE(/* ... */), DIGITAL_READ(/* ... */) UNKNOWN(null); public static CharacteristicHandler valueOf(UUID uuid) { /* ... */ } public UUID getUUID() { /* ... */ } public void handle() { /* ... */ } }
  37. 対策②: Callback のハンドリング  どの操作のコールバックかを判断するには, 引数に入ってるインスタンス見るしかない  普通にやると Callback Hell

    不可避  上手く処理を移譲させないとヤバい (数千行のなんちゃら Manager クラスとかと対峙するはめに…)
  38. 余談  イイ感じのパターンでラップしちゃうのもある e.g. Rx, Promise, Observer, flux

  39.  イイ感じのパターンでラップしちゃうのもある e.g. Rx, Promise, Observer, flux  出回ってる BLE

    デバイスの SDK はつらい (ハッカソンとかではそのことを念頭に置いた方がいい) 余談
  40.  イイ感じのパターンでラップしちゃうのもある e.g. Rx, Promise, Observer, flux  出回ってる BLE

    デバイスの SDK はつらい (ハッカソンとかではそのことを念頭に置いた方がいい)  BLE まわり,ユニットテストどうするの? (BluetoothGatt は final なので… ラッパー書くしかない?) 余談
  41.  BLE,基本的にはつらいです Conclusion

  42.  BLE,基本的にはつらいです  公式はあまり信用出来ない(過激派) Conclusion

  43.  BLE,基本的にはつらいです  公式はあまり信用出来ない(過激派)  状態遷移を意識しよう Conclusion

  44.  BLE,基本的にはつらいです  公式はあまり信用出来ない(過激派)  状態遷移を意識しよう  ガバガバ Callback からどうやって処理を

    ハンドリングしていくかが重要 Conclusion
  45. http://konashi.ux-xu.com/ https://github.com/YUKAI/konashi-android-sdk/ https://www.flickr.com/photos/36571434@N03/8524872002