在 Android 应用程序中找到蓝牙设备,但在 Flutter 的平台特定代码中找不到

Bluetooth devices found in an Android app, but not in a platform specific code in Flutter

我正在尝试扫描、连接蓝牙模块并从中接收数据。如果我只使用 android 应用程序,一切正常。我可以扫描并找到所有附近的设备,连接到任何人(我只对我的蓝牙模块感兴趣)并且我能够读取从蓝牙模块发送的测试数据。

问题是应用程序是使用 Flutter 开发的。我使用了我的 Android 应用程序中的相同代码,并通过 EventsChannel 将其与 Dart 链接,但现在我只能在 Flutter 应用程序中看到更少的蓝牙设备,其中 none 个是我正在使用的蓝牙模块感兴趣。我是 Flutter 和平台特定编码的新手,我不明白为什么相同的代码在相同硬件的不同应用程序中表现不同。

我在三星 S4 和 S8 手机上测试了我的代码,结果是一样的。

这是发现部分的 EventChannel 代码:

new EventChannel(flutterEngine.getDartExecutor(), DISCOVER_CHANNEL).setStreamHandler(
        new EventChannel.StreamHandler() {
          @Override
          public void onListen(Object args, EventChannel.EventSink events) {
            Log.w(TAG, "Registering receiver");
            discoverReceiver = DiscoverReceiver(events);
            IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
            registerReceiver(discoverReceiver, filter);
          }

          @Override
          public void onCancel(Object args) {
            Log.w(TAG, "Unregistering receiver");
            unregisterReceiver(discoverReceiver);
            discoverReceiver = null;
          }
        }
);

现在我的 discoverReceiver 是一个全局 BroadcastReceiver。 下面是 Broadcastreceiver 的代码:

private BroadcastReceiver DiscoverReceiver(final EventSink events) {
  return new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
      String action = intent.getAction();
      if (BluetoothDevice.ACTION_FOUND.equals(action)) {
        // Discovery has found a device. Get the BluetoothDevice
        // object and its info from the Intent.
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        String deviceName = device.getName();

        if (deviceName == null){
          deviceName = "No Device Name";
        }

        events.success(deviceName);
        Log.w(TAG, "Sending " + deviceName);
      } 
    }
  };
}

**我使用了 (Log.w(TAG, "Sending " + deviceName);) 语句来查看事件是否正在 lost/dropped。 下面是我在 Dart 中接收它的方式:

@override
  void initState() {
    super.initState();
    devices.add(selectDevice);
    discoverChannel.receiveBroadcastStream().listen(onEvent);
  }

  void onEvent(Object event) {
    setState(() {
      devices.add(event);
    });
  }

下面是我的 Android 应用程序中的代码,它可以扫描并找到所有设备,以防您想与上面的进行比较:

private BroadcastReceiver DiscoverReceiver() {
    return new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            // Discovery has found a device. Get the BluetoothDevice
            // object and its info from the Intent.
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            String deviceName = device.getName();

            if (deviceName == null){
                deviceName = "No Device Name";
            }
            devicelist.add(device);
            devNames.add(deviceName);
            arrayAdapter.add(deviceName);
            arrayAdapter.notifyDataSetChanged();
            Log.w(TAG, "Sending " + deviceName);
            }
        }
    };
}

我不关心最后一个片段,但我只是想展示完整的流程。片段 2 是我在独立 Android 应用程序中拥有的内容的副本,它会扫描并找到所有设备,但是一旦我在 Flutter 应用程序中将它用作 Android 的本机代码,它就会停止查找相同数量的设备,但仍然找到一些并且非常不可靠。

我已经尝试了大部分 Flutter 蓝牙包,但其中 none 正是我想要的,所以我最终选择了特定于平台的代码,在插入 Flutter 之前它工作正常。我已经阅读了 Android 开发文档,上面的代码大部分是 Android 示例中的修改代码。我只是不明白为什么相同的代码可以找到更多的设备作为独立应用程序,而不是将它用作 flutter 应用程序的本机代码,如果最后它是在相同的硬件上进行测试的话。

如有任何意见,我们将不胜感激!

好的,我终于找到了解决方案。这与蓝牙的 startDiscovery() 运行 和正常工作有关,但事件会在稍后捕获,这是调试器无法显示的。

所以在我的例子中,所有设备都是 "discovered" 但是 flutter 应用程序稍后开始捕获事件,因此它只显示在发现过程中发现的最后 1 或 2 个设备。

我搬家了:

discoverChannel.receiveBroadcastStream().listen(onEvent);

从 initState() 到按下按钮后调用的函数,这确保在本机端注册广播接收器和 Dart 的广播流接收器之前所有内容都已加载。

我还是不太清楚具体怎么表达,不过是关于在native端注册BroadcastReceiver,在Dart端注册receiveBroadcastStream的时机。

现在它开始发现并正确捕获事件,这显示在 Android 独立应用程序中找到的相同数量的设备。

希望这对以后可能会遇到这个奇怪问题的人有所帮助。