BLE设备仅返回20字符JSON,Flutter代码如何获取完整内容?
解决flutter_reactive_ble接收BLE JSON数据截断问题
问题根源
BLE默认MTU(最大传输单元)为23字节,其中3字节是协议开销,实际可传输的有效载荷只有20字节,这就是你每次只能拿到前20个字符的原因。其他应用正常是因为它们做了MTU协商和分片数据拼接处理。
修改方案
1. 协商更大的MTU
在连接BLE设备后,主动请求更大的MTU值(需设备支持,通常最大可到512),减少数据分片次数。
2. 实现分片数据缓冲与完整JSON校验
用StringBuffer缓冲接收的分片数据,每次接收后检查是否构成完整的JSON(可通过判断结尾符},或设备约定的分隔符如换行符\n),确认完整后再更新UI。
修改后的完整代码
import 'dart:async'; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; import 'dart:convert'; import 'widgets/ble.dart'; class TemperaturChartPage extends StatefulWidget { @override _TemperaturChartPageState createState() => _TemperaturChartPageState(); } final characteristicUuid = "19B10021-E8F2-537E-4F6C-D104768A1214"; final globalBluetoothData = GlobalBluetoothData(); final flutterReactiveBle = FlutterReactiveBle(); class _TemperaturChartPageState extends State<TemperaturChartPage> { final flutterReactiveBle = FlutterReactiveBle(); StreamSubscription<List<int>>? _bleSubscription; final StringBuffer _jsonBuffer = StringBuffer(); // 用StringBuffer缓冲分片数据 String displayJson = ''; // 用于展示的完整JSON内容 @override void initState() { super.initState(); _negotiateMtu(); // 先协商MTU _subscribeToTemperatureCharacteristic(); } // 协商更大的MTU,减少数据分片 void _negotiateMtu() async { if (globalBluetoothData.connectedDeviceId != null) { try { // 请求MTU为512,设备不支持则返回自身最大值 await flutterReactiveBle.requestMtu( deviceId: globalBluetoothData.connectedDeviceId!, mtu: 512, ); print("MTU协商成功"); } catch (e) { print("MTU协商失败: $e"); } } } void _subscribeToTemperatureCharacteristic() { if (globalBluetoothData.connectedDeviceId != null && globalBluetoothData.serviceUuid != null) { final characteristic = QualifiedCharacteristic( serviceId: Uuid.parse(globalBluetoothData.serviceUuid!), characteristicId: Uuid.parse(characteristicUuid), deviceId: globalBluetoothData.connectedDeviceId!); _bleSubscription = flutterReactiveBle .subscribeToCharacteristic(characteristic) .listen((data) { _processIncomingData(data); }, onError: (dynamic error) { print("BLE数据接收错误: $error"); }); } } // 处理分片数据,拼接并校验JSON完整性 void _processIncomingData(List<int> data) { String newChunk = utf8.decode(data); _jsonBuffer.write(newChunk); // 拼接新收到的分片 String currentBuffer = _jsonBuffer.toString(); // 先通过结尾符初步判断,再用jsonDecode验证合法性 if (currentBuffer.endsWith('}')) { try { jsonDecode(currentBuffer); // 解析成功说明是完整JSON setState(() { displayJson = currentBuffer; }); _jsonBuffer.clear(); // 清空缓冲,准备接收下一段JSON } catch (e) { // 解析失败,说明数据还不完整,继续缓冲 print("JSON不完整,继续接收分片: $e"); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Temperature Chart"), ), body: SingleChildScrollView( child: Column( children: <Widget>[ Padding( padding: const EdgeInsets.all(8.0), child: Text(displayJson), ), ], ), ), ); } @override void dispose() { _bleSubscription?.cancel(); super.dispose(); } }
关键说明
- MTU协商:
requestMtu需在设备连接成功后调用,不同设备支持的最大MTU不同,若请求值超过设备上限,会自动返回设备支持的最大值。 - 数据缓冲:使用
StringBuffer比直接拼接字符串更高效,避免频繁创建字符串对象。 - 完整性校验:通过
jsonDecode尝试解析是最可靠的方式,能确保拿到的是合法的完整JSON;如果设备发送的JSON有固定分隔符(如换行),也可以用分隔符来判断是否接收完成。
内容的提问来源于stack exchange,提问作者hurtstocode
相关产品推荐
相关产品推荐

