基於CoreBluetooth與藍牙4.0設備通訊非常方便,一句話總結就是中心-設備-服務-特徵,對應的關鍵API爲CBCentralManager-CBPeripheral-CBService-CBCharacteristic。
可以通過LightBlue查看你的藍牙設備相關信息,也可以發送簡單指令。
CBCentralManager scanForPeripherals時需要注意兩點:
- APP需要後臺掃描withServices必須指定要掃描的服務的UUID,不傳系統會忽略不執行後臺掃描;
- 指定服務UUID無法找到設備,可能是芯片不支持在沒有連接的情況下掃描服務。如果確實需要就找芯片開發溝通,非必要就掃描所有設備再通過設備名稱等過濾連接後再找到服務。
設定特徵uuid爲:
private let Characteristic_UUID: String = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
一、使用中心對象查找設備
centralManager = CBCentralManager.init(delegate: self, queue: .main)
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
print("unknown")
case .resetting:
print("resetting")
case .unsupported:
print("unsupported")
case .unauthorized:
print("unauthorized")
case .poweredOff:
print("poweredOff")
case .poweredOn:
print("ok")
central.scanForPeripherals(withServices: [], options: nil)
}
}
二、連接設備並查找服務
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
self.peripheral = peripheral
// 根據設備名稱來過濾
if ((peripheral.name != nil) && (peripheral.name?.hasPrefix("XXX"))!) {
central.connect(peripheral, options: nil)
central.stopScan();
}
}
三、獲取指定服務,查詢指定特徵
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service: CBService in peripheral.services! {
print("設備中的服務有:\(service)")
}
//假設外設中只有一個服務
let service = peripheral.services?.last
//根據UUID尋找服務中的特徵
peripheral.discoverCharacteristics([CBUUID.init(string: Characteristic_UUID)], for: service!)
}
四、發現指定特徵
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
for characteristic: CBCharacteristic in service.characteristics! {
print("外設中的特徵有:\(characteristic)")
}
self.characteristic = service.characteristics?.last
}
五、向特徵發送十六進制指令
此特徵必須是約定的可寫入特徵(是否可寫入與設備的通訊協議一般都會定好,也可以通過LightBlue查看),指令通訊一般是十六進制指令,假設指令爲打開(0x2601),爲方便操作封裝一個十六進制字符串轉data的方法:
func dataWithHexString(hex: String) -> Data {
var hex = hex
var data = Data()
while(hex.count > 0) {
let subIndex = hex.index(hex.startIndex, offsetBy: 2)
let c = String(hex[..<subIndex])
hex = String(hex[subIndex...])
var ch: UInt32 = 0
Scanner(string: c).scanHexInt32(&ch)
var char = UInt8(ch)
data.append(&char, count: 1)
}
return data
}
調用此方法:
if peripheral == nil || characteristic == nil {
print("no peripheral connected")
return;
}
let data = dataWithHexString(hex: "2601")
peripheral?.writeValue(data, for: characteristic!, type: CBCharacteristicWriteType.withoutResponse)
這裏需要注意,一般的寫入操作CBCharacteristicWriteType的類型是withResponse需要設備有響應,但是具體設備要看芯片設計,如果發現沒有成功嘗試使用withoutResponse。
寫入有響應會回調:
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
print("寫入數據")
}
簡單的基於CoreBluetooth發送指令就介紹這些,如果涉及與藍牙設備大數據傳輸代碼和通訊協議相對較複雜,另外還需要注意發送數據的間隔,因爲限於載波大小如果單次數據較大可能會沒有響應,間隔參考值: