繁体   English   中英

flutter_blue:Android 上的 set_notification 和 read_characteristic 错误,BLE 设备在第一次连接尝试时断开连接

[英]flutter_blue: set_notification and read_characteristic errors on Android, BLE device disconnects on first connection attempt

我已经与 flutter 合作了几个星期,并且正在尝试构建一个应用程序来通过 BLE 与移动电源进行通信。 在其当前的 state 中,它在 iOS 上正常工作。 在 android 上,部分由于 BLE 设备的行为,我在连接/发现阶段抛出了异常。

详细信息和版本控制

  • Flutter:1.17.5
  • 颤振蓝:0.7.2
  • 目标 Android 设备:运行 Android 10 的 Google Pixel 3A
  • 目标 iOS 设备:iPhone XS 运行 13.6,iPhone 6s 运行 iOS 12

代码

void connect(String deviceId) async {
    var dev = devices[deviceId];
    if (connectedDevices[deviceId] != null) return;
    await dev.device.connect(autoConnect: false);

    dev.connection = dev.device.state.listen((state) async {
      dev.deviceState = state;
      notifyListeners();
      if (state == BluetoothDeviceState.disconnected) {
        connectedDevices[dev.id] = null;
        await dev.dispose();
        notifyListeners();
      }

      if (state == BluetoothDeviceState.connected) {
        dev.services = await dev.device.discoverServices();
        for (BluetoothService service in dev.services) {
          // set services based on uuid
        }
        for (BluetoothCharacteristic characteristic
            in dev.deviceInfoService.characteristics) {
          // set characteristics from services
        }
        for (BluetoothCharacteristic characteristic
            in dev.notificationService.characteristics) {
          switch (characteristic.uuid.toString()) {
            case notificationServiceCharacteristic:
              dev.notificationServiceCharacteristic = characteristic;
              if (!dev.notificationServiceCharacteristic.isNotifying) {
                await dev.notificationServiceCharacteristic
                    .setNotifyValue(true);
                dev.valueChangedSubscription = dev
                    .notificationServiceCharacteristic.value
                    .listen((value) {
                  _onValuesChanged(dev, value);
                  notifyListeners();
                });
                connectedDevices[dev.id] = dev;
              }
              break;
            case writeCharacteristic:
              dev.writeCharacteristic = characteristic;
              break;
            default:
              break;
          }
        }
        notifyListeners(); //using scopedModel for handling state
        await readServiceCharacteristics(dev);
      }
    });
  }

应该发生什么

程序连接到设备。 连接后(状态 == BluetoothDeviceState.connected),发现服务和特征。 找到通知服务后,通过回调打开通知以处理数据。 完成此操作后,从只读特征中读取。

怎么了

在 iOS 设备上,没有明显的错误。 程序正常运行; 尽管是由 BLE 设备引起的初始断开连接。 尝试重新连接成功,没有失败。

在 Android 上:抛出异常: /flutter ( 1557): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(set_notification_error, error when writing the descriptor, null)

负责线路:

await dev.notificationServiceCharacteristic
                    .setNotifyValue(true);

为什么会发生 / BLE 设备错误

在我的研究中,我似乎已经找到了该错误的原因之一。 无论出于何种原因,BLE 设备都不会在第一次连接尝试时完成连接过程。 典型的连接工作如下:

  • 连接调用
  • 已连接设备
  • 代码的服务发现/通知部分被调用
  • 设备已断开连接
  • 再次调用连接
  • 发现/通知部分正常运行,设备保持连接
  • 程序接收通知

调试步骤

  • 首先,我从forEach切换到for(BluetoothService service in dev.services) “for-in” 样式,因为这样可以确保迭代等待回调/返回。

  • 在调试中,我可以使用断点来确保程序不会抛出异常。 通过在等待行放置一个断点并等待一两秒钟,它可以正常工作。 在没有设置断点的情况下运行代码每次都会抛出错误,不会失败。

  • 我用 RaisedButtons 构建了一个简单的 PoC 来调用初始化、扫描、连接和断开功能。 错误仍然存在

  • 很明显,在设备的 state 的 StreamListener 中,它来自

    • 连接的
    • 断开连接(此时我可以通过断开连接和处理连接或通过注释掉它再次尝试来在逻辑上停止)
    • 在我不处理和断开连接的情况下,它会再次切换到连接

想法

虽然我知道这个问题部分是由 BLE 设备本身引起的,但我想知道是否有任何方法可以解决这个问题或解决它。 我正在考虑的一个想法是终止异步调用并设置某种标志的方法,以便在随后的调用中,程序知道清理和/或延迟以确保它可以正常工作。

我看过的一些 github 问题似乎遇到了类似的问题 - 解决方案通常是强制延迟或(在完美的世界中)没有最初断开连接的设备。 我将链接一些上下文:

PlatformException(set_notification_error, error when writing the descriptor, null) on setNotifyValue #295

特征是在设备重新连接时发送重复通知 #525 (不完全相同,但重复触发让我认为它并不太遥远)

无论哪种方式,感谢您的阅读,我希望尽快摆脱我身边的这根刺!

我不想冒犯你,但你的代码很难阅读。 首先,我建议您应该使用一些约定。 像 Future 一样,if 后面的花括号将这个巨大的方法分解成更小的方法。 我以前见过这个错误。 在这里,我建议一些解决方案。

  • 在交换机中,您开始收听一个 stream。 在 function 的末尾,您正在尝试读取特征。 我不确定您的 POC 是否同时支持多种方法。 当您收听 stream 时,我会删除 readServiceCharacteristics 或从阅读开始并等待它完成,然后启动 stream 监听器。
  • 当您通知听众也许您尝试在 BLE 设备上读取或写入时,很难说出发生了什么。 去掉它。 走着瞧吧。

所以基本上尽量使用特性,尽量避免并行请求。 希望对您有所帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM