从蓝牙Characteristic读取长属性值时无法一次性获取完整数据
解决BLE特征值一次性读取128字节数据的问题
你遇到的是BLE默认MTU(最大传输单元)限制的问题。BLE协议默认MTU为23字节,其中1字节用于操作指令,所以实际能承载的用户数据只有22字节。要一次性读取完整的128字节数据,需要先与外设协商更大的MTU值,具体实现步骤如下:
1. 连接外设后主动请求扩展MTU
在外设连接成功的代理方法中,调用requestMTU(_:)请求更大的MTU。由于你需要读取128字节数据,建议请求185字节的MTU(该值在多数BLE 4.2及以上设备中都支持,足够容纳128字节用户数据):
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { // 请求扩展MTU peripheral.requestMTU(185) peripheral.delegate = self }
2. 监听MTU更新结果
实现peripheral(_:didUpdateMTU:error:)代理方法,确认MTU是否协商成功,成功后再执行服务和特征值的发现操作:
func peripheral(_ peripheral: CBPeripheral, didUpdateMTU mtu: Int, error: Error?) { if let error = error { print("MTU协商失败: \(error.localizedDescription)") // 协商失败时,只能退而处理分块读取逻辑 peripheral.discoverServices([CBUUID(string: "FFA1")]) return } print("MTU已更新为: \(mtu)") // MTU协商成功,开始发现目标服务 peripheral.discoverServices([CBUUID(string: "FFA1")]) }
3. 修改特征值读取逻辑
保持你原有的特征值发现和读取逻辑,但确保这部分代码在MTU协商完成后执行。此时读取特征值就能一次性获取完整的128字节数据:
public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { guard error == nil, let characteristics = service.characteristics else { print("发现特征值失败: \(error?.localizedDescription ?? "未知错误")") return } if service.uuid.uuidString == "FFA1" { for characteristic in characteristics { peripheral.setNotifyValue(true, for: characteristic) if characteristic.uuid.uuidString == "FFF3" { peripheral.readValue(for: characteristic) print("找到设备名称特征值") print("\(characteristic)") if let value = characteristic.value { print("完整数据: \(value as NSData)") // 这里可以直接处理128字节的完整数据 } } } } }
关键注意事项
- 外设必须支持BLE 4.2或更高版本,且固件中配置了允许扩展MTU,否则无法协商更大的MTU
- 如果外设不支持扩展MTU,你只能通过分块读取的方式拼接完整数据(监听
peripheral(_:didUpdateValueFor:error:)多次回调并累加数据) - 请求的MTU值不能超过外设支持的最大值,否则会被自动调整为外设支持的最大MTU
内容的提问来源于stack exchange,提问作者Gopi Gowda
相关产品推荐
相关产品推荐

