【Swift UI】Core BluetoothでPeripheralの実装方法!アドバタイズとは?

この記事からわかること
- Swift UIでCore BluetoothでBluetooth接続アプリの実装方法
- Peripheral側の実装
- ServiceとCharacteristicの実装方法
- Centralに値を渡すには?
index
[open]
- Core Bluetoothとは?
- 実装するにあたって
- 「Read」「Write」「WriteWithoutResponse」「Notify」「Indicate」の違い
- Peripheral機能の実装方法
- Privacy - Bluetooth Peripheral Usage Descriptionキーの追加
- Bluetooth機能管理クラスの作成
- サービス/キャラクタリスティックのUUIDを定義
- CBPeripheralManagerDelegateへの準拠
- サービス/キャラクタリスティックを追加する
- アドバタイズの実装
- Readリクエストの検知
- Writeリクエストの検知
- Notifyを送信する
- おすすめ参考書:iOS×BLE Core Bluetoothプログラミング
\ アプリをリリースしました /
今回はiOSアプリでBluetooth機能を実装するためにCore Bluetoothを使用してPeripheral側の実装方法をまとめていきます。この記事とCentral側も実装することで実際にBluetooth機能をテストできるアプリが完成できるのでハンズオンで試してみてください。
Core Bluetoothとは?
Core BluetoothはアプリからBLE(Bluetooth Low Energy)を使用するための機能を提供するライブラリです。デフォルトで組み込まれているので導入作業は必要なくすぐに使用することができます。
Bluetooth接続を用いる場合は例えばPCとキーボードなど接続しあう2つの登場人物が必要になります。2つのうちBluetoothの機能を使用する親側を「Central(セントラル)」、機能を提供する子側を「Peripheral(ペリフェラル)」と呼びます。例で言うとPCがセントラル、キーボードがペリフェラルです。
そしてペリフェラルが持っている機能のまとまりをサービス、機能1つ1つをキャラクタリスティックと呼びます。
iOSアプリ側もセントラルであることが多いですが、もちろんペリフェラルとして実装することも可能になっています。
実装するにあたって
Xcodeで実装するにあたってシミュレーターではBluetooth機能をサポートしていないのでテストする際には実機が必要になります。ペリフェラル側との連携を試したい場合は実機が2台に必要になるので注意してください。
また今回の全体のコードはGitHubに掲載しています。
「Read」「Write」「WriteWithoutResponse」「Notify」「Indicate」の違い
Bluetoothでデータはキャラクタリスティックを介して操作されますが、キャラクタリスティックには属性が付与されそれぞれ特徴が異なります。先にざっと確認しておきます。
Read
Readは読み取りをするための属性です。
Write
Writeは書き込みをするための属性です。
WriteWithoutResponse
WriteWithoutResponseは書き込みをするための属性です。Writeとは違い応答がありませんがその分高速にデータの書き込みが可能です。
Notify
Notifyは通知をするための属性です。データの変更があった際に通知することができます。
indicate
Indicateは通知を示唆をするための属性です。Notifyと同じくデータの変更があった際に通知が飛びますが、クライアントが通知を受信したことを確認する必要があります。
Peripheral機能の実装方法
流れ
- Privacy - Bluetooth Peripheral Usage Descriptionキーの追加
- Bluetooth機能管理クラスの作成
- サービス/キャラクタリスティックのUUIDを定義
- CBPeripheralManagerDelegateへの準拠
- サービス/キャラクタリスティックを追加する
- アドバタイズの実装の実装
- ペリフェラルの検出と接続
- サービス一覧を取得する
- キャラクタリスティック一覧を取得する
- ペリフェラルから値を取得する
Core Bluetoothではスキャンや探索などの処理を実行すると結果がデリゲートメソッドから取得できる仕組みが多用されています。デリゲートについて詳しく知りたい方は以下の記事を参考にしてください。
Privacy - Bluetooth Peripheral Usage Descriptionキーの追加
iOSアプリでBluetooth機能を使用するためには「info.plist」に以下の2つのキーを追加します。
value
には「アプリ内でBluetooth機能を使用するため」など、Bluetooth機能を使用する理由を記述しておきます。
Bluetooth機能管理クラスの作成
Bluetooth機能を管理するためのBluePeripheralManager
クラスを作成します。この際にimport CoreBluetooth
も合わせて記述しておきます。Peripheralとしての機能を使用する提供するCBPeripheralManager
型のperipheralManager
プロパティをとシングルトン用のプロパティを定義しておきます。
またペリフェラルの名称をperipheralNameプロパティに保持しておきます。ここで指定した値でCentral側とPeripheral側がお互いを認識できるようにしておきます。また後で使用するのでinit
もオーバーライドしておきます。
サービス/キャラクタリスティックのUUIDを定義
さらにペリフェラルに持たせるサービスとキャラクタリスティックのUUIDと保持用のプロパティを定義します。UUIDはCBUUID
クラスのイニシャライザを使用してCBUUID
型で定義しておきます。UUID(Universally Unique IDentifier)とはSwift独自のものではなく識別子の標準規格です。128bit(=16byte)の数値として表されます。
これで下準備の完成です。
CBPeripheralManagerDelegateへの準拠
公式リファレンス:CBPeripheralManagerDelegate
続いてCBPeripheralManagerDelegate
にBluePeripheralManager
クラスを準拠させていきます。CBPeripheralManagerDelegate
のデリゲートメソッドからPeripheralとしての状態などを取得することが可能です。準拠させることでperipheralManagerDidUpdateState(_: CBPeripheralManager)
デリゲートメソッドの実装が必須になります。これはPeripheralの状態が変化するタイミングで呼ばれます。
引数のperipheral
のstate
プロパティから現在の状態をCBManagerState型で取得できます。以下は状態に応じて分岐させているコードです。
最後にCBPeripheralManagerDelegate
に準拠したことでperipheralManager
プロパティにCBPeripheralManager
インスタンスを格納できるようになります。引数delegate
にはself(自身)
をqueue
にはnil
を渡しておきます。
サービス/キャラクタリスティックを追加する
ペリフェラルにサービスとキャラクタリスティックを追加していきます。addService
メソッドを定義してその中に記述していきます。サービスはCBMutableService
をインスタンス化します。イミュータブルなCBService
もあるので間違えないように注意してください。
CBMutableServiceの引数
- type:サービスのUUID
- primary: true / false
続いてCBMutableCharacteristic
をインスタンス化します。イミュータブルなCBCharacteristic
もあるので間違えないように注意してください。今回は4種類のキャラクタリスティックを準備していきます。
CBMutableCharacteristicの引数
- type:キャラクタリスティックのUUID
- properties:read / write(writeWithoutResponse) / notify / indicate (複数指定したい場合は配列で渡す)
- value:nil 初期値にデータを渡すことも可能だが後から更新できなくなるので注意
- permissions:readable / writeable (複数指定したい場合は配列で渡す)
最後にservice.characteristics
に配列形式のキャラクタリスティックを追加し、peripheralにサービスを追加します。
addService
メソッドが完成したのでperipheralManagerDidUpdateState
の中のpoweredOn
状態で呼び出しておきます。poweredOn
状態に入る前に追加処理を実行しても正常に追加できない場合があるので注意してください。
CBPeripheralManagerDelegate
に準拠したことでperipheralManager(_ :, didAdd service: , error:)
がサービス追加時に呼ばれるようになります。
アドバタイズの実装
セントラル側と接続するためにペリフェラル側からはアドバタイズを実行します。これは自身が接続可能状態で存在することをアピールする動作になります。実行するにはstartAdvertising
メソッドを使用し、引数にペリフェラル側の情報(名前や保有するサービス)を渡しておきます。そのためにはadvertisementData
の中に辞書形式で情報を構築していきます。キー値にはCBAdvertisementDataLocalNameKey
やCBAdvertisementDataServiceUUIDsKey
などあらかじめ定義されているものを使用します。
これでアドバタイズの際に名前やサービス情報を一緒に含ませることができます。これをすることでセントラル側からペリフェラルを識別しやすくなります。
scanForPeripherals
メソッドは明示的にstop
するまでスキャンし続けてしまい電池を無駄に消耗してしまうので、後述するstopScan
メソッドを使用して適切なタイミングでのスキャンの停止の実装が必要です。(例えば10秒のタイマーを設置するなど)
またCBPeripheralManagerDelegate
に準拠したことでperipheralManagerDidStartAdvertising(_:, error:)
はアドバタイズ成功時に呼ばれるようになります。
これでペリフェラル側の基礎的な実装は完了です。startAdvertising
を呼び出せばペリフェラルからアドバタイズが開始され、セントラルのスキャンとあえば2つの端末が接続されます。
ここからは追加でペリフェラル側からセントラルから送られたreadやwriteなどのリクエストを検知し処理を実装する方法をまとめていきます。
Readリクエストの検知
セントラルからread
リクエストが届くとperipheralManager(_ :, didReceiveRead request:)
デリゲートメソッドが呼ばれます。この際にセントラル側に返す値をコントロールすることが可能です。返却したいデータを作成しrequest.value
に格納します。
peripheralManager
からrespond
メソッドを呼び出しrequest
と成功失敗のフラグをCBATTError
型で指定すればOKです。
Writeリクエストの検知
セントラルからwrite
リクエストが届くとperipheralManager(_ :, didReceiveWrite requests:)
デリゲートメソッドが呼ばれます。この中でセントラル側から送られてきた値をコントロールすることが可能です。
Notifyを送信する
ペリフェラルからNotifyを送信するためにはupdateValue
メソッドを使用します。引数に送信したいデータ、キャラクタリスティックを渡します。これはデリゲートメソッドではないのでButtonと紐付けて明示的に呼び出す必要があります。
おすすめ参考書:iOS×BLE Core Bluetoothプログラミング
iOSアプリでBLEを使用した機能を実装したいなら一度は読んでおくことをおすすめする参考書です。iOSでのCore Bluetoothを使用した実装だけでなく、Bluetoothに関する細かい知識やノウハウも詰まっているので網羅的に理解したい方にはバッチリだと思います。
少し古い参考書であり、Objective-CとSwift両方のコードで実装方法が記述されています。Swift UIでの実装方法は載っていませんが、基本的なコードは昔からあまり変わっていないのでつまづくところはなく実装できると思います。
BLEを食材や店員などに例えて解説してくれるので素人でもBLEの概念がつかみやすく記述されています。約500ページくらいあるのでボリュームがすごいですが、ここから得られる知識は数知れませんでした。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。