使用flutter_reactive_ble读取BLE设备特征值失败求助
使用flutter_reactive_ble读取BLE设备时间的问题与解决方案
问题描述
在使用flutter_reactive_ble包读取低功耗蓝牙设备特征值时,触发以下GATT异常:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Exception: GenericFailure
(code: CharacteristicValueUpdateError.unknown, message: "GATT exception from MAC address FF:24:01:06:20:E4, with type BleGattOperation{description='CHARACTERISTIC_READ'}")
当前已实现的可正常运行的代码:
1. 扫描设备
getDevice() { Uuid u1 = Uuid.parse('00001800-0000-1000-8000-00805f9b34fb'); Uuid u2 = Uuid.parse('00001801-0000-1000-8000-00805f9b34fb'); Uuid u3 = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb'); flutterReactiveBle.scanForDevices(withServices: [u1, u2, u3], scanMode: ScanMode.lowLatency).listen((device) { setState(() { name = device.name; id = device.id; }); }); }
2. 连接设备
connectToDevice() { Uuid ser = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb'); Uuid cha = Uuid.parse('00000001-0000-1000-8000-00805f9b34fb'); flutterReactiveBle.connectToDevice( id: id, servicesWithCharacteristicsToDiscover: {ser: [cha]}, connectionTimeout: const Duration(seconds: 10), ).listen((connectionState) { setState(() { able = connectionState.connectionState.name; }); }); }
3. 报错的读取代码
尝试读取设备时间时触发异常:
readFromDevice() async { Uuid ser = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb'); Uuid cha = Uuid.parse('0000fff1-0000-1000-8000-00805f9b34fb'); final characteristic = QualifiedCharacteristic(serviceId: ser, characteristicId: cha, deviceId: id); final response = await flutterReactiveBle.readCharacteristic(characteristic).then((value) { print(value.toString()); }); print(response.toString()); }
设备文档说明:
- Characteristic UUID:0xFFF2(属性:write,APP向设备发送指令)
- Characteristic UUID:0xFFF1(属性:Notify,设备向APP推送数据)
- 获取仪表时间需发送指令:
0x01
解决方案
错误核心原因
你试图用readCharacteristic读取属性为Notify的0xFFF1特征,但Notify类型的特征不支持主动读取操作,只能通过订阅监听设备推送的数据。同时,获取时间的逻辑是先向0xFFF2写入指令,再通过0xFFF1接收返回结果。
修正后的代码实现
1. 更新连接时的特征发现
连接时需同时发现0xFFF1(Notify)和0xFFF2(Write)两个特征:
connectToDevice() { Uuid ser = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb'); Uuid chaNotify = Uuid.parse('0000fff1-0000-1000-8000-00805f9b34fb'); Uuid chaWrite = Uuid.parse('0000fff2-0000-1000-8000-00805f9b34fb'); flutterReactiveBle.connectToDevice( id: id, servicesWithCharacteristicsToDiscover: {ser: [chaNotify, chaWrite]}, connectionTimeout: const Duration(seconds: 10), ).listen((connectionState) { setState(() { able = connectionState.connectionState.name; }); }); }
2. 订阅Notify特征接收设备数据
在获取时间前,先监听0xFFF1的推送事件:
StreamSubscription? _timeNotifySubscription; void startListeningToMeterTime() { Uuid ser = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb'); Uuid chaNotify = Uuid.parse('0000fff1-0000-1000-8000-00805f9b34fb'); final characteristic = QualifiedCharacteristic( serviceId: ser, characteristicId: chaNotify, deviceId: id ); _timeNotifySubscription = flutterReactiveBle.subscribeToCharacteristic(characteristic) .listen((data) { // 根据设备协议解析Uint8List格式的时间数据 print('设备返回时间数据: $data'); // 示例解析(需按实际协议调整) // String formattedTime = _parseTimeFromBytes(data); // setState(() { meterTime = formattedTime; }); }, onError: (error) { print('监听时间推送失败: $error'); }); }
3. 写入指令触发设备返回时间
向0xFFF2特征发送0x01指令:
Future<void> sendGetMeterTimeCommand() async { Uuid ser = Uuid.parse('0000fff0-0000-1000-8000-00805f9b34fb'); Uuid chaWrite = Uuid.parse('0000fff2-0000-1000-8000-00805f9b34fb'); final characteristic = QualifiedCharacteristic( serviceId: ser, characteristicId: chaWrite, deviceId: id ); try { await flutterReactiveBle.writeCharacteristicWithoutResponse( characteristic, value: Uint8List.fromList([0x01]) ); print('已发送获取时间指令'); } catch (e) { print('写入指令失败: $e'); } }
4. 清理资源
在页面销毁或断开连接时取消订阅,避免内存泄漏:
@override void dispose() { _timeNotifySubscription?.cancel(); super.dispose(); }
注意事项
- 必须确保设备处于
connected状态后,再执行订阅和写入操作。 - 数据解析需严格遵循设备提供的协议文档,不同设备的字节格式、编码方式可能不同。
- 写入指令时,根据设备要求选择
writeCharacteristic(带响应)或writeCharacteristicWithoutResponse(无响应)。
内容的提问来源于stack exchange,提问作者Serenity Emmanuel
相关产品推荐
相关产品推荐

