Android-BLE-Library

こんにちは、アプリケーションエンジニアの難波です。

BraveridgeではIoTデバイスを製作する時によくNordic社のSoCを使用しています。
そのNordic社はAndroid用のBLEライブラリをOSSとしてリリースしています。

AndroidアプリでBLE機能を実装しようとすると、OSのバージョンや機種依存、ハマりやすいポイント等があったりと結構クセが強いです。
NordicのAndroid用BLEライブラリはその辺りを良い感じに吸収してくれています。

  1. Android-Scanner-Compat-Library
  2. Android-BLE-Library

今回は Android-BLE-Library のCentralに関連する機能を実装例と共に紹介します。

実装例

Centralを実装する時に BLEデバイスのスキャン と BLEデバイスに接続して制御 という2機能を実装する必要があります。 
このライブラリは BLEデバイスへの接続と制御 を担当します。
Android-BLE-LibraryはCentralだけでなくPeripheralを実装する場合にも利用することができます。

1. BleManager を継承したclassを実装します。
このclassでBLEデバイスへの接続・切断とcharacteristicのread、write、notifyのcallbackを実装します。


class SampleBleManager(context: Context) : BleManager(context) {
    var discoveredServicesHandler: ((List<BluetoothGattService>) -> Unit)? = null

    private var gattCallback: BleManagerGattCallback? = null

    private inner class SampleBleManagerGattCallback: BleManagerGattCallback() {
        //	Peripheral接続後にコールされる
        public override fun isRequiredServiceSupported(gatt: BluetoothGatt):Boolean {
            discoveredServicesHandler?.apply { this(gatt.services) }
            return true
        }

        override fun onDeviceDisconnected() {}
    }

    //  親クラスのコンストラクタでコールされる
    override fun getGattCallback() = gattCallback ?: run {
        gattCallback = SampleBleManagerGattCallback()
        gattCallback!!
    }
}

BleManagerGattCallback の実装

まず BleManagerGattCallback を実装します。(SampleBleManagerGattCallbackクラス)
BLE接続が完了すると isRequiredServiceSupported(gatt) がコールされます。
この時点で接続したPeripheralのServiceリストを取得しているので、discoveredServicesHandler でViewModelやActivityなど呼び出し側に伝えます。

getGattCallback() の実装

次に getGattCallback() を実装します。
このメソッドは親クラスのコンストラクタでコールされるので、SampleBleManagerクラス のコンストラクタよりも先に getGattCallback() が呼ばれます。
そのため gattCallbackプロパティ をnullチェックして、初回コール時のみ SampleBleManagerGattCallbackクラス をインスタンス化しています。


val connectionObserver = object: BaseConnectionObserver {} 
//  ↑ BaseConnectionObserver は ConnectionObserver の各メソッドをデフォルト実装したインターフェース
    
val bleManager: SampleBleManager by lazy {
    val manager = SampleBleManager(app)
    manager.setConnectionObserver(connectionObserver)
    manager.discoveredServicesHandler = { services -> 
        services.forEach { Log.d(TAG, it.uuid.toString()) } 
    }
    manager
}

//  Peripheralに接続する
val bluetoothDevice: BluetoothDevice  // BLEスキャンで取得したBluetoothDeviceインスタンス
bleManager.connect(bluetoothDevice).enqueue()

//  Peripheralとの接続を切断する
bleManager.disconnect().enqueue()



実装した SampleBleManagerクラス をインスタンス化してPeripheralに接続します。
BleManagerクラス では以下の機能が実装されているので、SampleBleManagerクラス で簡単に利用する事ができます。

  • RSSIの取得
  • characteristicの操作(read、write、notifyのcallback)
  • MTUの変更
  • ボンディング(ペアリング)

メリット

よくある実装ミスとして、Peripheralへ上記操作を複数同時並行にリクエストしてしまい、Peripheral側がいくつかのリクエストをスルーしてしまう事があります。
BleManagerクラス では内部にリクエストキューを実装しているので、必ずシーケンシャルに実行してくれます。
こういった機能はとてもありがたいです。

サンプルアプリを含めたソースコード全体は github で確認できます。

SNS SHARE