如何開發iOS Swift BLE通訊 (QCA402X BLE應用)

前言

在物聯網時代,許多硬體須透過藍牙低功耗技術(BLE, Bluetooth Low Energy)與手機APP做應用。在iOS開發中,藍牙開發框架是使用Core Bluetooth,本文會介紹在iOS環境中Core Bluetooth與藍牙設備通信所需要的類與協議,以及介紹如何與QCA402X BLE做交互。

I. 宣告所需要的許可權

(圖一)在info.plist內新增

Privacy Bluetooth Peripheral Usage Descriptionkey


此外,在最新的iOS13上需要再新增“Privacy – Bluetooth Always Usage Description”key到info.plist中(圖二)。


(圖二)在info.plist內新增

Privacy Bluetooth Always Usage Descriptionkey


II. 關鍵類

其中主要關鍵的類別為“CBCentralManager”和 “CBPeripheral”。

· CBCentralManager: 藍牙的控制中心,此類別主要用於對外部設備進行搜尋、發現以及連接。
· CBPeripheral: 此類別代表每一個外圍藍牙設備對應一個CBPeripheral對象,通過對應的外圍藍牙設備獲取RSSI值、發送數據以及讀取數據,且外圍設備由通用唯一標識符(UUID)表示為NSUUID對象,可能包含一項或多項服務。


III. 藍牙開發流程
  1. 連線藍牙前的初始化工作
  2. 掃描藍牙裝置
  3. 連線藍牙裝置
  4. 發現服務
  5. 收發資料
  6. 斷開連線
IV. 連線藍牙前的初始化工作

第一步驟要先設置CBCentralManager進行藍牙管理(圖三)。

初始化

(圖三)初始化CBCentralManager



V. 掃描藍牙裝置

在startScan()裡面新增CBCentralManager的scanForPeripherals功能掃描外圍設備(圖四),當掃描開始進行時,會調用CBCentralManagerDelegate裡的didDiscover peripheral方法(圖五),這樣一來就可以得到外部設備的名稱以及RSSI。若要停止掃描則需執行CBCentralManger裡的stopScan功能(圖六)。

(圖四)調用CBCetralManager裡的scanForPeripherals功能進行掃描


(圖五)當正在進行掃描時,調用CBCetralManagerDelegate裡“centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPripheral, advertisementData: [String: Any], rssi RSSI: NSNumber)”的方法


(圖六)調用CBCetralManager裡的stopScan功能停止掃描



VI. 連線藍牙裝置

首先,連線第一步驟必須調用“CBCentralManager”裡的connect方法,如(圖七)所示,在先前已經宣告“var centralManager: CBCentralManager!”,所以這邊直接調用方法centralManager.connect(peripheral, options: nil)進行連線。

(圖七)調用方法centralManager.connect(peripheral, options: nil)


若連線成功後會調用CBCentralManagerDelegate裡didConnect peripheral的方法(圖八),如果連線失敗則會調用didFailToConnect peripheral (圖九)”。

(圖八)當連線成功,調用CBCentralManagerDelegate裡 “centralManager(_ central: CBCentralManager, didConnect peripheral: CBPripheral)”的方法


(圖九)當連線失敗,調用CBCentralManagerDelegate裡“centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPripheral, Error?)



VII. 發現服務、特徵、特徵符

當連線成功後,即可讀取peripheral的service、characteristic以及descriptor。

didDiscoverServices:找尋服務

此時調用CBPeripheralDelegate裡didDiscoverServices的方法來讀取peripheral的service (圖十),再利用for迴圈讀取service所包含的characteristic。

(圖十)調用CBPeripheralDelegate裡 “peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)”的方法來讀取peripheral的service


當讀取到peripheral所包含的characteristic後則調用CBPeripheralDelegate裡didDiscoverCharacterisiticFor service的方法來讀取service底下的characterisitic (圖十一),如圖所示,讀取到service下的所有characterisitic,並利用for迴圈將characteristic對應先前已宣告的uuid,如果對應成功就可以調用CBPeripheral.setNotifyValue(enable: Bool, for: CBCharacterisitic)的方法可以對characteristic收到回傳的通知。最後可以再調用CBPeripheral裡的discoverDescriptors來讀取每個characteristic下的descriptor。

(圖十一)調用CBPeripheralDelegate裡 “peripheral(_ peripheral: CBPeripheral, didDiscoverCharacterisiticFor service: CBService,  error: Error?)”的方法來讀取service底下的characterisitic


而descriptor還需透過CBPeripheralDelegate裡didDiscoverDescriptorFor characterisitic的方法來讀取descriptor(圖十二)。

(圖十二)透過CBPeripheralDelegate裡 “peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorFor characterisitic: CBCharacterisitic,  error: Error?)”的方法來讀取descriptor


VIII. 收發資料

完成上述步驟後,要透過手機BLE與QCA402X進行交互就必須透過發送資料以及接收資料這兩項步驟。如(圖十三) 所示,利用writeValueForCharacteristic的方法將值寫入characteristic,如果是以CBCharacteristicWriteWithResponse模式發送,就可以調用CBPeripheralDelegate的didwriteValueFor characteristic的方法(圖十四)判斷發送是否成功,如果是以CBCharacteristicWriteWithoutResponse模式則不能使用該方法判斷。

(圖十三)利用writeValueForCharacteristic(hex: Data, forCharacteristic characteristic: CBCharacteristic)的方法將值寫入characteristic


(圖十四)調用CBPeripheralDelegate的(peripheral_ peripheral: CBPeripheral, didwriteValueFor characteristic: CBCharacteristic, error: Error?)的方法判斷發送是否成功

當收到數據時,會調用didUpdateValueFor characteristic的方法 (圖十五),就可以接收到數據。(圖十五)中self.delegate?.readData(characteristic: characterisitic, peripheral: peripheral)的方法是利用Delegate將資料傳到UI層進行顯示。

(圖十五) peripheral(_ peripheral: CBperipheral, didUpdateValueFor characteristic: CBCharacterisitic, error: Error?)的方法接收數據


QCA402X範例: 

可以自行在QCA402X開發板上定義Turn On / Turn Off LED的指令,這樣一來就可以在手機APP上進行LED開關控制。在Xcode中將On(0x00) / Off(0x01)的指令透過writeValueForCharacterisitic的方法將值寫入後, 再透過readData來讀取回傳的資料,即可分析LED當前的狀態為On或Off。圖十六、圖十七為App上LED燈控制按鈕ON與OFF,當按下後收到回傳的資料即會調出alert,顯示如圖十八、圖十九。



 (圖十六) LED ON
   (圖十七) LED OFF

(圖十八) Alert(ON)
   (圖十九) Alert(OFF)

IX. 斷開連線

調用(圖二十)didDisconnectPeripheral peripheral的方法執行斷線。

(圖二十)調用centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)


X. 總結

本文主要介紹如何使用Xcode開發iOS BLE、介紹Core Bluetooth iOS藍牙框架和兩個主要關鍵的類別“CBCentralManager”和“CBPeripheral”以及流程中各個重要方法的介紹以及應用,按照第三點“藍牙開發流程”中的步驟即可開發出一款基本的iOS藍牙通信APP。

★博文內容均由個人提供,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★文明上網,請理性發言。內容一周內被舉報5次,發文人進小黑屋喔~

評論

Yoyo

Yoyo

2021年1月19日
因無法排版 導致程式碼看起來很凌亂 有問題歡迎再提問,謝謝!
Yoyo

Yoyo

2021年1月19日
peripheralFound是遵從自己定義的delegate 所以需要定義在class之上,還包含其他function: public protocol BLEControllerDelegate: NSObjectProtocol { func peripheralFound(peripheral:CBPeripheral, rssi:NSNumber) func serviceDiscoverEnd() func readData(characteristic:CBCharacteristic, peripheral:CBPeripheral) func setConnect() func setDisconnect() } 在class內定義 static var shareStore = BLEController(); //自己設定的ViewController weak var delegate: BLEControllerDelegate? 這樣就可以引用delegate.peripheralFound(peripheral:CBPeripheral, rssi:NSNumber)
銳

2020年12月8日
您好,請教一下 peripheralFound 是遵從哪個delegate?