You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 00:43:13