CoreBluetoothを使ってBLE Peripheral側を実装する
最終更新日:2022-05-11
CoreBluetoothのAPIを使うと、データを提供するPeripheral側も実装することができます。次の4ステップで実装します。
- CBPeripheralManagerを作る
- サービスを追加する
- Advertiseを開始する
- Readリクエストが来た時の処理を実装する
順にみていきましょう。
CBPeripheralManagerを作る
まずはviewDidLoad()のあたりでCBPeripheralManagerオブジェクトを作ります。今回はdelegateにself(=ViewController)を指定したので、ViewControllerにCBPeripheralManagerDelegateプロトコルをつけます。また、サービスとCharacteristicのUUIDを表すオブジェクトも作っておきます。
class PeripheralViewController : UIViewController, CBPeripheralManagerDelegate {
var serviceUUID : CBUUID!
var characteristicUUID : CBUUID!
var manager : CBPeripheralManager!
var service : CBMutableService!
var characteristic : CBMutableCharacteristic!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.serviceUUID = CBUUID(string: Constants.SERVICE_UUID)
self.characteristicUUID = CBUUID(string: Constants.CHARACTERISTIC_UUID)
self.manager = CBPeripheralManager(delegate : self, queue : nil)
}
}
オブジェクトを作ると、早速CBPeripheralManagerDelegateのperipheralManagerDidUpdateState()
が呼ばれます。端末のBluetoothがOFFの場合は次の図のようにダイアログが出ます。
<img src="./bluetooth_off.webp"/>
BluetoothがONの時のみ、後続の処理を行うようperipheralManagerDidUpdateState()
を実装します。
func peripheralManagerDidUpdateState(peripheral: CBPeripheralManager!) {
if (peripheral.state == CBPeripheralManagerState.PoweredOn) {
self.addMessage("BLE Power On")
// この時点でサービスを登録する(次節参照)
self.addService()
}
}
サービスを追加する
次にサービスを追加します。今回はCharacteristicを1つだけ持ったサービスを作ってみます。
func addService() {
self.service = CBMutableService(type: self.serviceUUID, primary: true)
self.characteristic = CBMutableCharacteristic(type: self.characteristicUUID,
properties: CBCharacteristicProperties.Read,
value: nil, permissions:
CBAttributePermissions.Readable)
self.service.characteristics = [self.characteristic]
self.manager.addService(self.service)
}
CBMutableCharacteristicのvalueの部分は、Readリクエストが来た時に動的に値を返したい場合はnilを指定します。
Advertiseを開始する
サービスの追加まで完了したら、次はAdvertiseを開始します。Advertiseを開始するには、CBPeripheralManagerのstartAdvertising()
を使います。
self.manager.startAdvertising([CBAdvertisementDataServiceUUIDsKey : [self.service.UUID]])
引数には、CBAdvertisementDataServiceUUIDsKeyキーを持つDictionaryを指定します。このキーの値はサービスのUUIDを配列で指定します。型チェックの効かない部分なので不用意に[]を抜いたりしてはまらないよう注意します。
このメソッドを呼ぶと、CBPeripheralManagerDelegateのperipheralManagerDidStartAdvertising:error()
が呼ばれます。errorがnilであればAdvertiseは開始されています。
func peripheralManagerDidStartAdvertising(peripheral: CBPeripheralManager!, error: NSError!) {
if (error == nil) {
self.addMessage("Start advertisement")
} else {
self.addMessage("Failed to start advertisement " + error!.localizedDescription)
}
}
Readリクエストが来た時の処理を実装する
Central側がReadリクエストを投げると、CBPeripheralManagerDelegateのperipheralManager:didReceiveReadRequest()
が呼ばれます。ここでCentral側に値を通知します。
func peripheralManager(peripheral: CBPeripheralManager!, didReceiveReadRequest request: CBATTRequest!) {
self.addMessage("Receive request")
if (!request.characteristic.UUID!.isEqual(self.characteristic.UUID)) {
return
}
if (request.offset > data.length) {
self.manager!.respondToRequest(request, withResult: CBATTError.InvalidOffset)
return;
}
// create data
request.value = self.data!.subdataWithRange(NSMakeRange(request.offset, data.length - request.offset))
self.manager!.respondToRequest(request, withResult: CBATTError.Success);
self.addMessage("Respond to request");
}
データの長さとオフセットの関係がおかしい場合はCBATTError.InvalidOffset
を返しておきます。正常な場合はrequest.value
にデータをセットし、ResultにCBATTError.Success
をセットし返します。