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

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

次に 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 で確認できます。