如何用CoreBluetooth(Swift)判断BLE设备配对及didWriteValueFor未调用问题
一、didWriteValueFor未调用的原因及修复
结合你提供的代码,以下是导致代理未触发的核心问题及修复方案:
1. 重复调用服务发现
在didConnect方法中,你同时调用了connectedPeripheral?.discoverServices()和peripheral.discoverServices(nil),这会导致逻辑冗余且可能引发回调混乱。只需保留一次服务发现调用即可:
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { peripheral.delegate = self peripheral.discoverServices(nil) // 仅保留这一行 }
2. 错误的特征写入判断
你仅给具备.notify属性的特征写入值,但支持notify的特征通常用于接收设备推送,不一定支持write操作。必须检查特征是否包含.write或.writeWithoutResponse属性:
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { if let error = error { print("发现特征失败: \(error.localizedDescription)") return } guard let characteristics = service.characteristics else { return } let value = 1234 // 按设备要求调整数据格式,比如转为小端字节序 let data = withUnsafeBytes(of: value.littleEndian) { Data($0) } for characteristic in characteristics { // 仅给支持写入的特征写值 if characteristic.properties.contains(.write) || characteristic.properties.contains(.writeWithoutResponse) { peripheral.writeValue(data, for: characteristic, type: .withResponse) } // 单独处理notify订阅 if characteristic.properties.contains(.notify) { peripheral.setNotifyValue(true, for: characteristic) } } }
3. 未处理服务/特征发现错误
原代码未处理didDiscoverServices和didDiscoverCharacteristicsFor中的error参数,若服务或特征发现失败,会直接跳过写入步骤,添加错误打印可快速排查问题:
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { if let error = error { print("发现服务失败: \(error.localizedDescription)") return } guard let services = peripheral.services else { return } for service in services { peripheral.discoverCharacteristics(nil, for: service) } }
4. 代理队列问题
初始化CBCentralManager时使用主队列(queue: nil),可能因主线程阻塞导致代理回调延迟或丢失,建议指定专用串行队列:
override init() { super.init() let bleQueue = DispatchQueue(label: "com.yourapp.ble", attributes: .serial) centralManager = CBCentralManager(delegate: self, queue: bleQueue) }
5. 数据格式不匹配
你写入的Int类型数据可能不符合设备期望的格式(如字节序、长度、编码方式),需对照设备文档调整数据转换逻辑。
二、可靠判断设备是否已配对的方法
CoreBluetooth无直接的配对状态API,可通过以下方式判断:
检查连接加密状态(iOS 13+)
配对后的连接会处于加密状态,可通过外设的securityLevel判断:if peripheral.isConnected && peripheral.securityLevel == .encrypted { // 已配对且连接加密 }监听系统配对回调
当系统弹出配对请求时,CBCentralManagerDelegate的centralManager(_:didReceiveAuthenticationRequest:)会被触发,处理完成后即可确认配对完成。尝试写入需加密的特征
若某特征需配对才能写入,写入失败会返回CBATTError.insufficientEncryption错误,此时可触发配对流程;写入成功则说明已配对。对比系统配对列表
通过系统API获取已配对设备UUID列表,对比当前外设的UUID:import CoreFoundation func isPeripheralPaired(_ peripheral: CBPeripheral) -> Bool { guard let pairedDevices = CNCopyPairedDevices() as? [CFDictionary] else { return false } for device in pairedDevices { if let uuidString = CFDictionaryGetValue(device, kBluetoothDeviceUUIDString as UnsafeRawPointer) as? String, UUID(uuidString: uuidString) == peripheral.identifier { return true } } return false }
内容的提问来源于stack exchange,提问作者Hakan Or

