Flutter BLE设备读写异常:返回数据解码为空求助
我帮你梳理下问题出在哪,以及给出正确的BLE读写实现方案:
问题分析
你遇到的解码为空问题,本质是数据接收逻辑的时机和方式错误,具体有这几个核心问题:
- 发送命令后立即断开连接
在_sendCommandToDevice方法里,写完命令马上调用disconnect(),此时设备大概率还没完成响应并推送数据,直接断开自然拿不到返回值。 - 错误的读取时机 + 未监听Notify回调
你在服务发现阶段就主动调用characteristic.read(),这时候还没发送命令,设备没有返回数据,读到的只是特征的初始空值。而BLE设备的响应数据通常是通过Notify/Indicate主动推送给客户端的,不是靠主动读取一次。 - 未启用Notify功能
即使找到了带notify属性的特征,也需要先调用setNotifyValue(true)开启通知,否则设备不会主动推送数据给Flutter端。
正确的BLE读写实现代码
我基于你的代码修改了核心逻辑,重点修复数据监听和命令发送的时机:
1. 先定义全局变量管理特征和订阅
BluetoothCharacteristic? _writeChar; // 用于发送命令的特征 BluetoothCharacteristic? _notifyChar; // 用于接收设备返回的特征 StreamSubscription<List<int>>? _notifySubscription; // 通知订阅,用于接收数据
2. 修改服务发现逻辑,正确启用Notify并监听回调
void _discoverDeviceServices() async { for (BluetoothService service in _services) { for (BluetoothCharacteristic characteristic in service.characteristics) { // 匹配可写入的特征(用于发送AT命令) if (characteristic.properties.write || characteristic.properties.writeWithoutResponse) { _writeChar = characteristic; } // 匹配可通知的特征(用于接收设备返回) if (characteristic.properties.notify) { _notifyChar = characteristic; // 必须先启用Notify,设备才会推送数据 await characteristic.setNotifyValue(true); // 订阅通知回调,这里才是接收返回数据的正确位置 _notifySubscription = characteristic.value.listen((rawData) { print("设备返回原始字节: $rawData"); // 尝试ASCII解码(你的命令是ASCII,返回大概率也是ASCII) String asciiResult = AsciiDecoder().convert(rawData); print("ASCII解码结果: $asciiResult"); // 如果ASCII解码有问题,试试兜底方案 String charCodeResult = String.fromCharCodes(rawData); print("字符码转换结果: $charCodeResult"); // 拿到数据后,再根据需求决定是否断开连接 // _connectedDevice.disconnect(); }); } } } // 服务发现完成后再发送命令 _sendCommandToDevice(); }
3. 修改命令发送方法,移除立即断开逻辑
void _sendCommandToDevice() async { if (_writeChar == null) { print("未找到可写入的BLE特征"); return; } final command = "AT Z\r"; final convertedCommand = AsciiEncoder().convert(command); // 写入命令,建议用writeWithoutResponse如果不需要设备确认写入成功 await _writeChar!.write(convertedCommand, withoutResponse: false); // 不要立即断开,等待notify回调拿到数据后再处理 }
4. 页面销毁时清理资源(避免内存泄漏)
@override void dispose() { // 取消通知订阅 _notifySubscription?.cancel(); // 断开设备连接 _connectedDevice?.disconnect(); super.dispose(); }
额外注意事项
- 确认命令格式:有些设备要求命令结尾是
\r\n而非\r,可以尝试把命令改成"AT Z\r\n"测试。 - 核对特征UUID:确保你选中的读写/通知特征是设备文档指定的UUID,避免选错特征导致数据无法交互。
- 排查原始字节:如果解码后还是空,先看打印的
rawData是否为空。如果原始字节有值但解码异常,可能是包含不可打印ASCII字符,可逐个打印字节值排查:rawData.forEach((byte) => print("字节值: $byte"))。
内容的提问来源于stack exchange,提问作者vibu
相关产品推荐
相关产品推荐

