Android-BLE-Library (Peripheral)
こんにちは、アプリケーションエンジニアの難波です。
BraveridgeではIoTデバイスを製作する時によくNordic社のSoCを使用しています。
そのNordic社はAndroid用のBLEライブラリをOSSとしてリリースしています。
AndroidアプリでBLE機能を実装しようとすると、OSのバージョンや機種依存、ハマりやすいポイント等があったりと結構クセが強いです。
NordicのAndroid用BLEライブラリはその辺りを良い感じに吸収してくれています。
今回は Android-BLE-Library のPeripheralに関連する機能を実装例と共に紹介します。
実装例
BleServerManager の継承
Centralの場合と比べて少し複雑になります。
まず BleServerManager を継承したclassを実装します。
このclassでPeripheralのProfileを定義します。
class SampleBleServerManager(private val context: Context)
: BleServerManager(context) {
val characteristicForRead = characteristic(
UUID.randomUUID(),
BluetoothGattCharacteristic.PROPERTY_READ,
BluetoothGattCharacteristic.PERMISSION_READ
).apply {
value = byteArrayOf(0x1)
}
private val serviceUUID = UUID.randomUUID()
override fun initializeServer() = listOf(service(serviceUUID, characteristicForRead))
}
initializeServer() の戻り値がBLE接続時にCentralが取得するServiceリストになります。
上の例ではread用のcharacteristicを含むserviceを定義しています。
Advertiseの実装
Advertiseは Android-BLE-Library の範囲外なので自分で実装する必要があります。
class SampleBleServerManager(private val context: Context)
: BleServerManager(context) {
// 追加
fun startAdvertising() {
val adviserSettings = AdvertiseSettings.Builder()
.build()
val advertiseData = AdvertiseData.Builder()
.addServiceUuid(ParcelUuid(serviceUuid))
.build()
val advertiseCallback = object : AdvertiseCallback() {}
// Advertise開始
BluetoothAdapter.getDefaultAdapter().bluetoothLeAdvertiser
?.startAdvertising(adviserSettings, advertiseData, advertiseCallback)
}
}
BleManager の継承
次にCentralとの接続から切断までを制御するために BleManager を継承したclassを実装します。
BleManager はCentralの実装時にも登場しましたが、Peripheralを実装するときも使用します。
class SampleConnectedBleManager(context: Context)
: BleManager(context) {
private var gattCallback: BleManagerGattCallback? = null
private inner class GattCallback : BleManagerGattCallback() {
override fun isRequiredServiceSupported(gatt: BluetoothGatt) = true
override fun onDeviceDisconnected() {}
}
override fun getGattCallback() = gattCallback ?: run {
gattCallback = GattCallback()
gattCallback!!
}
}
BLE接続された時
最後に BleServerManager に接続された時に BleManager を関連づけます。
class SampleBleServerManager(private val context: Context)
: BleServerManager(context) {
private val connectionObserver = object: BaseConnectionObserver {}
private val serverObserver = object: ServerObserver {
override fun onServerReady() {
// advertise開始
startAdvertising()
}
override fun onDeviceConnectedToServer(device: BluetoothDevice) {
// BleServerManager と BleManager を関連づける
val connectedManager = SampleConnectedBleManager(context)
connectedManager. setConnectionObserver(connectionObserver)
connectedManager.useServer(this)
connectedManager
.connect(device)
.enqueue()
}
override fun onDeviceDisconnectedFromServer(device: BluetoothDevice) {}
}
init {
setServerObserver(serverObserver)
}
}
SampleBleServerManager#open() をコールすると SampleBleServerManager#initializeServer() が実行され、Peripheralとしての動作準備を行います。
動作準備が完了すると SampleBleServerManager#onServerReady() がコールされるので、Advertiseを開始してPeripheralとして動作します。
val bleServerManager = SampleBleServerManager(context)
bleServerManager.open()
メリット
Peripheralを実装するには接続したCentralのBluetoothDeviceインスタンスを管理する必要がありますが、BleServerManager を利用するとその必要もありません。
またCentralとのコミュニケーションを BleManager が行うので、リクエスト・レスポンスのキューを実装する必要がありません。
AndroidのBLE処理をきちんと実装するとコード量が多くなりがちですが、Android-BLE-Libraryを利用すると結構コンパクトに実装できます。
サンプルアプリを含めたソースコード全体は github で確認できます。