Swift与Arduino通信:如何用advertisementData填充外设服务?
问题本质
BLE外设广播的服务UUID(存在advertisementData里)和CBPeripheral对象的services属性是两回事:
- 广播数据是外设主动发送的简短识别信息,受广播包大小限制,可能只包含部分服务UUID,不会自动填充到
CBPeripheral的services属性中 CBPeripheral的services只有在连接外设后,调用discoverServices()并通过peripheral(_:didDiscoverServices:)代理回调,才会被系统填充真实的服务列表,这是BLE协议规定的标准流程
解决方案:自定义模型存储广告数据
系统的CBPeripheral是只读的系统类,无法直接修改它来填充广播服务信息。正确做法是创建自定义模型,将CBPeripheral、广播服务UUID、RSSI等信息打包存储,这样就能在列表中展示广告中的服务内容。
1. 定义自定义设备模型
import CoreBluetooth struct BluetoothDevice { // 系统提供的外设对象 let peripheral: CBPeripheral // 广播中携带的服务UUID列表 let advertisedServiceUUIDs: [CBUUID]? // 当前信号强度 let rssi: NSNumber }
2. 修改didDiscover方法存储自定义模型
把原来直接存储CBPeripheral的逻辑,改成存储自定义的BluetoothDevice:
// 调整devices数组的类型为[BluetoothDevice] var devices: [BluetoothDevice] = [] func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { // 从广告数据中提取服务UUID let advertisedUUIDs = advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] let newDevice = BluetoothDevice(peripheral: peripheral, advertisedServiceUUIDs: advertisedUUIDs, rssi: RSSI) // 检查设备是否已存在,不存在则添加,存在则更新RSSI等数据 if let existingIndex = devices.firstIndex(where: { $0.peripheral.identifier == peripheral.identifier }) { devices[existingIndex] = newDevice } else { devices.append(newDevice) } }
3. 连接逻辑保持不变
连接时直接使用自定义模型里的peripheral属性即可,原有连接和服务发现流程无需修改:
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { isConnected = true selectedDevice = peripheral selectedDevice?.delegate = self selectedDevice?.discoverServices([targetServiceUUID]) }
额外说明
- 广播里的服务UUID仅适合提前筛选外设(比如只保留包含目标服务UUID的设备),不能作为完整服务列表依赖——因为广播包大小有限,外设可能不会把所有服务都放入广播
- 只有连接后通过
discoverServices()获取的peripheral.services,才是外设真实的完整服务列表,这一步是与外设通信的必要流程,无法跳过
内容的提问来源于stack exchange,提问作者Grapefruit
相关产品推荐
相关产品推荐

