如何在蓝牙适配器被禁用并重新启用后使 Android 连接?

How to make Android connect after the Bluetooth Adapter has been disabled & reenabled?

我编写了一个连接到 BLE 设备的应用程序。该应用程序在大多数设备上运行正常;但某些设备(最明显的是华为 P8 Lite 和 Nexus 6P)在禁用蓝牙适配器后拒绝连接。

这是测试序列:

  1. 确保该应用不是 运行。
  2. 从顶部向下滑动,禁用 BT 几秒钟,然后重新启用蓝牙。
  3. 启动应用程序。该应用程序会自动连接到存储在首选项中的蓝牙地址。
  4. 等待连接。这是华为 phones 没有发生任何事情的地方,但其他 phones,例如三星,就像一个魅力。
  5. 从另一个验证 phone 该设备正在投放广告,您可以 连接到它。

这是我用来连接的代码:

private final Runnable mBeginConnectRunnable = new Runnable() {
    @Override
    public void run() {
        synchronized (GattConnection.this) {
            if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
                try {
                    mBluetoothAdapter.cancelDiscovery();
                    mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(mAddress);
                    mGatt = mBluetoothDevice.connectGatt(mContext, mBackgroundConnect, mGattCallback);
                    final boolean connectSuccess = mGatt.connect();
                    Log.d(TAG, String.format(Locale.ENGLISH, "mGatt.connect(%s, %s) %s",
                            mAddress,
                            mBackgroundConnect ? "background[slow]" : "foreground[fast]",
                            connectSuccess ? "success" : "failed"));
                    refreshDeviceCache(mGatt);

                } catch (Exception ex) {
                    Log.e(TAG, "Create connection failed: " + ex.getMessage());
                    setState(State.Closed);
                }
            } else {
                Log.d(TAG, "Can't create connection. Adapter is disabled");
                setState(State.Closed);
            }
        }
    }
};

所有调用都通过处理程序发布到主线程。我可以看到它等待连接,在 30 秒后放弃,我在对象上调用 BluetoothGatt.close() 并将其清空。外面好像什么都没有。

一段时间后,在当天晚些时候,它再次工作。

非常感谢您的帮助:-)

2018 年 9 月 14 日更新:经过 Emil 的精彩解释后,我更新了我们的应用程序,因此在 Nexus 上没有这个问题。我注意到 Huawei P8 Lite 继续在后台扫描,似乎您无法阻止它。

为了演示问题,我制作了一个非常简单干净的应用程序,在 phone 上使用蓝牙 LE 功能并用它来演示这个问题,而且 P8 坏了。该应用程序可在此处获得:https://play.google.com/store/apps/details?id=eu.millibit.bluetootherror 来源可在此处获得:https://bitbucket.org/millibit/eu.millibit.bluetootherror/src/master/

我希望我可以随着时间的推移扩展此应用程序,使其成为 Android 的测试工具,记录来自 Android 的所有异常行为并将其收集到数据库中。如果你有兴趣贡献,请不要犹豫给我发邮件 bt.error@millibit.dk

Android 蓝牙堆栈在其 API 中存在设计缺陷。当您通过蓝牙设备地址连接到特定设备时,无法判断您指的是 Public 地址还是随机地址。

如果您使用 autoConnect=false 开始连接未绑定且最近未在扫描中看到的设备,它会假设您指的是 Public 地址。因此,如果您尝试连接到具有静态随机地址的设备,它将失败。

如果设备未绑定,为确保使用正确的地址类型连接,您必须先执行扫描,找到设备,然后开始连接尝试。