iOS之CoreBluetooth
- 2021 年 3 月 3 日
- 筆記
- CoreBluetooth, iOS, Object-c
-
思路
手機與設備間的通訊方式CoreBluetooth是比較常見且通用的。在iOS開發中需明晰以下幾點
- 藍牙4.0最多可聯機7個設備,iPhone6以上都是藍牙4.0
- 兩台iPhone並不直接通過藍牙互相搜索配對
- 蘋果設備不支援和其他非蘋果設備連接藍牙,當然,除了藍牙耳機和車載藍牙之外
- 藍牙傳輸的位元組順序是小端
- CoreBluetooth的最大傳輸單元是20個位元組
知識科普:
位元組順序只是對內置數據類型而言
例如對於一整型(int,int 是內置數據類型)數,比如 0x123456 大端模式: 高地址---------->低地址 0x56 | 0x34 | 0x12 小端模式: 高地址 ---------->低地址 0x12 | 0x34 | 0x56
-
流程
以中心設備為例分析整個流程
1.實例化中心設備管理者
cManager = CBCentralManager(delegate: self, queue: nil)
2.監測狀態為PowOn,並搜索附近設備
func centralManagerDidUpdateState(_ central: CBCentralManager) { if central.state == .poweredOn { scanForServices() } else { print("\(central.state)") } }
3.發現外設,保存並展示
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { if let name = peripheral.name { if !list.contains(name) { list.append(name) dict[name] = peripheral table.reloadData() } } }
4.根據需要選擇連接的外設
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // 連接設備 if let pheral = dict[list[indexPath.row]] { cManager?.connect(pheral, options: nil) } }
5.連接外設,失敗/成功,成功則掃描外設服務
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { print("連接外設失敗") } func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { // 停止掃描 central.stopScan() print("連接外設成功") peripheral.delegate = self self.peripheral = peripheral // 掃描外設的服務 peripheral.discoverServices([CBUUID(string: "列印")]) }
6.回調中發現服務
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { var findService: CBService? for item in peripheral.services ?? [] { print(item.uuid) // 如果服務調用在service中 if item.uuid.isEqual(CBUUID(string: "列印")) { findService = item } } if let findService = findService { peripheral.discoverCharacteristics(nil, for: findService) } }
7.查詢服務下面的特徵,回調中返回 then發送列印數據
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { for item in service.characteristics ?? [] { if item.uuid.isEqual(CBUUID(string: "列印")) { // 讀取成功回調didUpdateValueForCharacteristic self.characteristic = item // 接收一次(是讀一次資訊還是數據經常變實時接收視情況而定, 再決定使用哪個) peripheral.readValue(for: item) // 訂閱、實時接收 peripheral.setNotifyValue(true, for: item) // 發送下行指令【發送一條】 guard let data = "硬體工程師給我的指令, 發送給藍牙該指令, 藍牙會給我返回一條數據".data(using: .utf8) else { return } self.peripheral?.writeValue(data, for: item, type: .withResponse) } // 當發現characteristic有descriptor,回調didDiscoverDescriptorsForCharacteristic peripheral.discoverDescriptors(for: item) } }
8.從外圍設備讀取數據
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { //characteristic.value就是藍牙傳遞過來的值 print("\(String(describing: characteristic.value))") }
9.中心設備讀取外設實時數據
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { if characteristic.isNotifying { peripheral.readValue(for: characteristic) } else { print("notification stoped on \(characteristic)") self.cManager?.cancelPeripheralConnection(peripheral) } }
-
結束