先日まで、Android で Bluetooth デバイスと接続・通信する方法についての記事を書いていましたが、今度は同じことを iOS(Swift)で行います!
一度 Android で実装したからか、思ったよりも進捗状況はよく、現在はデバイスとの接続までが完了しています。
あとはデータ取得だけなのですが、取得できたデータの内容がおかしい…。
Android の時とは全く違う値を取得しているので、調査中です。
今回参考にさせていただいたサイトはこちらから。
iOS Core Bluetooth (Swift) を使用してみた – Grow up
https://knkomko.hatenablog.com/entry/2019/07/16/013443CoreBluetoothでNotificationを受け取る! – 野生のプログラマZ
http://harumi.sakura.ne.jp/wordpress/2018/11/08/corebluetooth-received-notification/iOS SwiftでBLEのサンプルを動かしてみる – Qiita
https://qiita.com/eKushida/items/def628e0eff6c106d467
さて実装方法ですが、まず CoreBluetooth をインポートし、Class に CBCentralManagerDelegate、 CBPeripheralDelegate を追加します。
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
    var centralManager: CBCentralManager?
    var myPeripheral: CBPeripheral?
    let serviceUUID: [CBUUID] = [CBUUID(string: "任意のUUID")]
    let characteristicsUUID: [CBUUID] = [CBUUID(string: "任意のUUID")]
    let descriptorUUID: [CBUUID] = [CBUUID(string: "任意のUUID")]
    override func viewDidLoad() {
        super.viewDidLoad()
        // centralManager の初期化
        centralManager = CBCentralManager(delegate: self, queue: nil)
    }
    
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch (central.state) {
        case .unknown:
            print(".unknown")
            break
        case .resetting:
            print(".resetting")
            break
        case .unsupported:
            print(".unsupported")
            break
        case .unauthorized:
            print(".unauthorized")
            break
        case .poweredOff:
            print(".poweredOff")
            break
        case .poweredOn:
            // Service UUID を指定してデバイスをスキャン
            centralManager!.scanForPeripherals(withServices: serviceUUID, options: nil)
            break
        }
    }
    ......
}
今回はデバイスを指定してスキャンを行なっております。
で、端末のスキャンができたら、下記の関数が呼び出されるため、こちらで接続の処理を行います。
// デバイスを検出したら呼ばれる
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,
                    advertisementData: [String : Any], rssi RSSI: NSNumber) {
    myPeripheral = peripheral
    print("device name: \(myPeripheral!.name!)")
    centralManager!.connect(myPeripheral!, options: nil)
}
なお、上記の参考サイトによると、接続するペリフェラルをメンバーとして保持しておかないと接続ができないのだそうです。
そのため、4行目で保持の処理を行なっています。
接続ができたら、サービスを検索します。
接続完了もしくは失敗時には下記の関数が呼び出されるため、成功時に .discoverServices() を使ってサービスの検索を行います。
// デバイスへの接続が成功すると呼ばれる
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    print("Connected!")
    myPeripheral!.delegate = self
    //指定されたサービスを探す
    myPeripheral!.discoverServices(serviceUUID)
}
// デバイスへの接続が失敗すると呼ばれる
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
    print("Connect failed...")
}
サービスが検索できたら、次はキャラクタリスティクスというものを見つけます。
サービス検索が完了できたときに呼び出される関数内で実行します。
// サービスの検索が成功したら呼ばれる
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    print("Discover Services")
    let service: CBService = myPeripheral!.services![0]
    myPeripheral!.discoverCharacteristics(characteristicsUUID, for: service)
}
上記までが完了したら、あとはデータを書き込んだり読み込んだりすることができます。
また、値が変化したことを検知することもでき、そちらは 8行目で定義しています。
で、実際に値が変化したら 17行目からの関数が呼び出されます。
// Characteristics を発見したら呼ばれる
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    print("Find Characteristics")
    let data = [送信したいデータ]
    //ペリフェラルの保持しているキャラクタリスティクスから特定のものを探す
    for i in service.characteristics!{
        if i.uuid.uuidString == "書き込みを行いたいUUID"{
            //Notification を受け取るというハンドラ
            peripheral.setNotifyValue(true, for: i)
            //書き込み
            peripheral.writeValue(data , for: i, type: .withResponse)
        }
    }
}
// Notificationを受け取ったら呼ばれる
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
    // valueの中にData型で値が入っている
    print(characteristic.value)
}
デバイスの検索からデータ取得までは以上で実装できます。
が、私の環境では、上記のコードを実行したところ、得られたデータが明らかにおかしいという状況になっています…。
十中八九、データの取得方法が間違っているのでしょうが、どう間違っているのかがまだわかっていません。
引き続き調査していきます。
以上、iOS の端末と Bluetooth デバイスを接続し、データを取得する方法でした。
とりあえず接続までは完了できたので、あともうちょっと頑張ります!
 
					         
               
                       
                