【Kotlin/Android】Bluetooth接続アプリCentral側の実装方法!

この記事からわかること
- Android Studio/KotlinでBluetooth接続アプリの実装方法
- Central側の実装
- ServiceとCharacteristicの取得方法
- peripheralから値を取得したり書き込むには?
- peripheralから更新通知を受け取る(notify)には?
index
[open]
\ アプリをリリースしました /
環境
- Android Studio:Koala
- Kotlin:1.9.0
今回はAndroidアプリでBluetoothでの接続機能を持ったCentral側の実装方法をまとめていきます。iOS側にはなってしまいますが実際の接続テストが行えるようにPeripheral側の実装も公開しているので参考にしてみてください。
AndroidのBluetooth機能の実装
Androidアプリでは「Classic Bluetooth」と「Bluetooth Low Energy(BLE)」の両方をサポートするBluetoothスタックがデフォルトで用意されています。これにより比較的簡単にBluetooth機能を実装することができるようになっています。
セントラルやペリフェラルという言葉が出てきましたがBluetoothで接続する側をセントラル、接続される側をペリフェラルと呼びます。よくあるBluetoothイヤホンで例えるとスマホがセントラルでイヤホンがペリフェラルになります。
AndroidアプリではBluetooth 4.1以降に対応しているデバイスでは「セントラル側」、「ペリフェラル側」問わず実装できるようになっています。古い端末だとペリフェラル側の実装はできないので注意してください。
今回は「Central側」の実装をしていきたいと思います。
実装するにあたって
Android Studioで実装するにあたってエミュレーターではBluetooth機能をサポートしていないのでテストする際には実機が必要になります。ペリフェラル側との連携を試したい場合は実機が2台に必要になるので注意してください。
Central機能の実装方法
流れ
- AndroidManifest.xmlに権限を追加
- Bluetooth有効管理クラスの実装
- ペリフェラル側のUUID定義
- BluetoothAdapterの取得
- スキャンの実装
- 接続する
- サービス一覧と各キャラクタリスティックを取得する
また今回の全体のコードはGitHubに掲載しています。
1.AndroidManifest.xmlに権限を追加
AndroidアプリでBluetooth機能を実装するためには「AndroidManifest.xml」に適切な権限を追加しておく必要があります。詳細は以下の記事を参考にしてください。
2.Bluetooth有効管理クラスの実装
アプリからBluetooth機能を使用するために「端末自体がBluetoothをサポートしているかどうかのチェック」と「権限のリクエスト処理&承諾チェック」をする必要があります。この処理は専用クラスにまとめて実装してみました。こちらも詳細はこちらを参考にしてください。
GitHub:BleActiveStateManager.kt
3.ペリフェラル側のUUID定義
今回はiOS側で実装したPeripheral側の機能に準ずる形で実装していきます。そのためUUIDは以下のように定義しておいてください。
4.BluetoothAdapterの取得
続いてBluetoothの有効状態やペアリング済みデバイスの取得などを行えるBluetoothAdapterを取得します。getSystemService(Context.BLUETOOTH_SERVICE)
からBluetoothManager
に参照できadapter
プロパティからBluetoothAdapter
を取得することが可能です。
5.スキャン処理の実装
続いて周辺からアドバタイズしているペリフェラル機器を検出するためにスキャン処理を実装します。スキャン処理はBluetoothLeScanner
型がスキャン結果のコールバックはScanCallback
型で実装します。プロパティとして保持できるように定義しておきます。
スキャン処理では最終的に接続対象のデバイスアドレスを取得することが目的です。そのデバイスアドレスを使用して後続の接続処理を実装していきます。スキャン処理の詳細は以下の記事を参考にしてください。
初回なのでわかりやすくするために接続処理に必要なスキャンで取得したデバイスアドレスをローカルに保存することで次回のスキャン処理をスキップできるように今回は実装してみました。
ただボンディングという機能を使用することでローカルに保存しなくてもデバイスアドレスを保持できる仕組みがあるので興味があればこちらを参考にしてください。
6.接続する
接続するにはBluetoothDevice
を取得してconnectGatt
メソッドを実行します。接続結果はBluetoothGattCallback
型から受け取ることができます。返り値でBluetoothGatt
を取得できるのでプロパティとして保持できるように定義しておきます。
コールバックのonConnectionStateChange
はペリフェラルとの接続状態が変化する際に呼ばれます。BluetoothProfile.STATE_CONNECTED
なら接続成功なので続いてdiscoverServices
でサービスの検索を行います。
7.サービス一覧と各キャラクタリスティックを取得する
discoverServices
でサービスの検索を実行するとBluetoothGattCallback#onServicesDiscovered
が呼ばれgatt.services
でサービス一覧を取得することが可能です。getService
を使用することで任意のサービス(BluetoothGattService
)を指定して取得することも可能なので、そこからgetCharacteristic
で対象のキャラクタリスティックを取得します。
これで端末(セントラル)が対象のペリフェラルと接続し、各キャラクタリスティックを取得できたことでデータの通信が可能な状態になりました。ここからは各キャラクタリスティックの使い方を見ていきます。
Readキャラクタリスティック
「Readキャラクタリスティック」は名前の通りペリフェラルから情報を取得するためのキャラクタリスティックです。値を読み取るにはreadCharacteristic
メソッドを実行します。
読み取った値はBluetoothGattCallback#onCharacteristicRead
から取得することが可能です。読み取れるデータはByteArray
型なので文字列に直したい場合は以下のように実装する必要があります。
読み取った値はBluetoothGattCallback#onCharacteristicRead
から取得することが可能です。読み取れるデータはByteArray
型なので文字列に直したい場合は以下のように実装する必要があります。
Writeキャラクタリスティック
「Writeキャラクタリスティック」は名前の通りペリフェラルに対して情報を書き込みするためのキャラクタリスティックです。値を書き込むためにはwriteCharacteristic
メソッドを実行します。TIRAMISU
でコードが少し分岐します。また書き込む値はByteArray
型です。
書き込みの成否はBluetoothGattCallback#onCharacteristicWrite
から取得することが可能です。BluetoothGatt.GATT_SUCCESS
であれば書き込みは成功です。
Notifyキャラクタリスティック
「Notifyキャラクタリスティック」は名前の通りペリフェラルからの通知を検知するためのキャラクタリスティックです。通知を受け取るためにはwriteCharacteristic
メソッドを実行します。TIRAMISU
でコードが少し分岐します。また書き込む値はByteArray
型です。
通知を検知するとBluetoothGattCallback#onCharacteristicChanged
から値を取得することが可能です。
※ しかしこちらのみ動作が確認できませんでした。動作確認が出来次第修正予定です。
切断処理の実装
ペリフェラルとの切断処理はdisconnect
メソッドを使用します。完了後はリソースを適切に開放する必要があります。
今回の全体のコードはGitHubに掲載していますので参考にしてください。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。