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

如何在Flutter中读取蓝牙设备更新后的Notify值?

问题:写入蓝牙设备后无法读取Notify值更新

向蓝牙设备写入数据后,尝试读取Notify值的更新,但使用Flutter_Blue_Plus包(包括官方示例应用)时,Notify值始终为空。用nRF Connect测试设备时,写入数据后能正常看到Notify值变化。

如何读取更新后的Notify值?

连接设备与发现服务的代码

List<ScanResult> result = [];
try {
  result = await FlutterBluePlus.instance.startScan(timeout: Duration(seconds: 5)) as List<ScanResult>;

  resultIndex = getResultIndex(result, event.dataTrac.sensor.dtId.getOrCrash());
} 
catch (ex){
  log("Scan failed because another scan was already in progress.");
}

try {
  if (resultIndex == -1){
    for (int i = 0; i < 5; i++){
      result = await FlutterBluePlus.instance.startScan(timeout: Duration(seconds: 5)) as List<ScanResult>;
      resultIndex = getResultIndex(result, event.dataTrac.sensor.dtId.getOrCrash());
      if (resultIndex > -1){
        break;
      }
    }
  }
}
catch (ex){
  log("Exception while scanning: $ex");
}

if (resultIndex > -1 && result.isNotEmpty){
  final ScanResult r = result.elementAt(resultIndex);
  //Make sure we aren't already connected to the device
  if (!(await FlutterBluePlus.instance.connectedDevices).contains(r.device)) {
    //log("Had not connected to device; connecting now");
    await r.device.connect(autoConnect: false);
    await r.device.mtu.first;
    final int response = await r.device.requestMtu(165);
    log("New Mtu: $response");
    final List<BluetoothService> serviceList = await r.device.discoverServices();
}

与设备交互的代码

for (final s in serviceList) {
  //log("Service UUID: ${s.uuid}", name: "programming_status_bloc.dart");
  if (s.uuid.toString() ==
      "6e400001-b5a3-f393-e0a9-e50e24dcca9e") {
    serviceFound = true;
    final actualTxChar = s.characteristics.firstWhere((element) => element.uuid.toString() == txChar);
    final success = await actualTxChar.setNotifyValue(true);
    if (success){
      log("Set notify value.");
    }
    else {
      log("**Failed to set notify value.**");
    }
    
    final actualRxChar = s.characteristics.firstWhere((element) => element.uuid.toString() == rxChar);
    //log("Char UUID: ${char.uuid}");
    if (continueWriting) {
      continueWriting = false;
      //TODO: change CID for production
      final List<int> payload = createPayload(event.dataTrac, event.changedValuesMap, 151);
      //final payload = [12, 12, 12, 12, 12, 0, 70];
      add(ProgrammingStatusEvent.updated(true));
      
      await actualRxChar.write(payload); 
      log("Wrote to device.");

      // final readResult = await actualRxChar.read();
      // log("Read result: $readResult");
    }  
    //r.device.disconnect();
    bool readYet = false;

    final txCharSubscription = actualTxChar.value.listen((value){
      log("Notify value: $value");
    });

    await Future.delayed(Duration(seconds: 4));
    await txCharSubscription.cancel();
    await r.device.disconnect();
    await FlutterBluePlus.instance.stopScan();                      
  }
}
if (!serviceFound){
  r.device.disconnect();
  await FlutterBluePlus.instance.stopScan();
}

解决方案

1. 调整订阅Notify的时机

当前代码先写入数据再订阅Notify流,会错过设备发送的响应。必须先订阅Notify,再执行写入操作,确保不会遗漏设备的反馈。

2. 确认特征UUID对应关系

检查txChar和rxChar的UUID是否正确:

  • txChar应为设备用于主动推送Notify的特征UUID
  • rxChar应为设备用于接收写入数据的特征UUID
    避免两者搞反导致无法接收数据。

3. 修改交互代码(修复版)

for (final s in serviceList) {
  if (s.uuid.toString() == "6e400001-b5a3-f393-e0a9-e50e24dcca9e") {
    serviceFound = true;
    final actualTxChar = s.characteristics.firstWhere((element) => element.uuid.toString() == txChar);
    final actualRxChar = s.characteristics.firstWhere((element) => element.uuid.toString() == rxChar);

    // 先订阅Notify流
    bool receivedNotify = false;
    final txCharSubscription = actualTxChar.value.listen((value) {
      if (value.isNotEmpty) {
        log("Notify value: $value");
        receivedNotify = true;
      }
    });

    // 开启Notify
    final success = await actualTxChar.setNotifyValue(true);
    if (!success) {
      log("**开启Notify失败**");
      await txCharSubscription.cancel();
      await r.device.disconnect();
      await FlutterBluePlus.instance.stopScan();
      continue;
    }
    log("已开启Notify");

    if (continueWriting) {
      continueWriting = false;
      final List<int> payload = createPayload(event.dataTrac, event.changedValuesMap, 151);
      add(ProgrammingStatusEvent.updated(true));
      
      // 写入数据
      await actualRxChar.write(payload); 
      log("已向设备写入数据");
    }  

    // 等待收到Notify或超时(可根据设备调整超时时间)
    int timeoutCount = 0;
    await Future.doWhile(() async {
      await Future.delayed(Duration(milliseconds: 500));
      timeoutCount += 500;
      return !receivedNotify && timeoutCount < 10000; // 10秒超时
    });

    // 清理资源
    await txCharSubscription.cancel();
    await r.device.disconnect();
    await FlutterBluePlus.instance.stopScan();                      
  }
}
if (!serviceFound){
  await r.device.disconnect();
  await FlutterBluePlus.instance.stopScan();
}

4. 额外排查点

  • 检查Notify特征是否支持指示(Indication):如果设备使用Indication而非Notification,需调用actualTxChar.setIndicateValue(true),并监听对应流。
  • 确认写入参数:actualRxChar.write(payload, withoutResponse: false),确保设备收到写入后会返回响应。
  • 验证特征属性:打印actualTxChar.properties,确认notify字段为true,确保该特征支持Notify功能。

内容的提问来源于stack exchange,提问作者TarHalda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 23:10:46