Android 6.0 Marshmallow BLE 连接问题

Posted

技术标签:

【中文标题】Android 6.0 Marshmallow BLE 连接问题【英文标题】:Android 6.0 Marshmallow BLE connectivity issues 【发布时间】:2016-10-30 11:57:55 【问题描述】:

我在使用 android 6.0 和一些低功耗蓝牙的设备时遇到了严重问题。其中一个有冲突的设备就是这个:

DEVICE INFO:
Name:         Samsung Galaxy SV  
Model number: SM-G900V  
Android vers: 6.0.1  
Patch level:  May 1, 2016  
Hard. vers:   G900V.05  

如果我根据应用程序与 BLE 外围设备的连接和断开连接进行压力测试,成功率几乎不会达到 50%。

阅读最新的 Android 文档,他们建议在 connectGatt 方法的最后一个参数中指定传输模式,以强制执行 BLE 传输连接而不是 BR/EDR:

device.connectGatt(this, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);

这次改进没有改变。

在阅读了一些suggestions 并阅读了有关 BLE 连接问题的信息后,我发现了一些与三星 Galaxy S6 相关的问题,在one of those 中,他们提出了一系列解决 BLE 连接问题的步骤。关键之一是clear Bluetooth Share system app 数据。这样做,连接率立即增加了几乎 100% 的成功率。但是,如果您等待并使用其他一些 BLE 应用程序并连接到其他外围设备,问题迟早会出现。

Google Play 中有 some apps 试图解决这些 BLE 问题,他们基本上做的是:

/system/bin/rm -r /data/misc/bluetoothd/*
/system/bin/rm -r /data/misc/hcid/*

虽然是清除蓝牙缓存的一种方式,但它需要设备root,这对于专业应用来说不是一个合理的解决方案。

我研究的所有私有 Android API 都没有帮助我解决这个问题,我发现的唯一一个类似的 API 是与问题无关的 enforce service discovery cache cleanup。

使用 BLE 数据包嗅探器,我发现 ADV_CONNECT_REQ 甚至没有从设备发送到外围设备,过了一会儿,Android 堆栈触发了 BluetoothGattCallback 中的 STATE_DISCONNECTED 事件。

我不完全知道为什么在某些 6.0 设备中会出现此问题,而在其他设备中则不会,因为蓝牙共享缓存似乎是问题所在。那里究竟存储了什么?只是以前连接/配对的设备?我是唯一遇到这个问题的人吗?如果不是,你们是怎么解决的?我不愿意指导最终用户如何清除蓝牙共享应用程序数据。

【问题讨论】:

在 S6 edge 上测试过,我可以确认,清除蓝牙共享缓存和数据帮助它连接,而无需传递 BluetoothDevice.TRANSPORT_LE 参数。我也不知道为什么会发生这种情况。在清除缓存之前,根本没有连接。 很高兴知道我不是唯一一个。感谢@CanCanbek 的反馈,希望有人可以帮助我们。 看了上面的内容,我明白了你的意思,6.0系统在S6 edge上,执行connectGatt()函数后,执行缓存操作,可以保证电话和通讯设备正常,不会有延误。是这个意思吗?@Can Canbek 我没有完美的解决方案,但发现调用 gatt dispose 并将其设置为 null 至少在一定程度上减少了这个问题。 我有一个 Moto X Play,BLE 设备发现在 Android 5.1.1 上运行良好。更新到 Android 6.0,它无法发现 BLE 设备。我也需要一个解决方案。在应用程序中,我调用 mBtAdapter.startLeScan(mLeScanCallback)。没有看到回调被调用。我从 Android Doc 中看到 startLeScan 方法在 API 级别 21 中已被弃用。 【参考方案1】:

有一个名为“removeBond”的隐藏方法。有时ble设备无法明确断开,此时需要调用remove bond。

来自here的代码

   //remove authrization 
   Method method = null; 
   try  
       method = gatt.getDevice().getClass().getMethod("removeBond", (Class[]) null); 
       method.invoke(gatt.getDevice(), (Object[]) null); 
    catch (Exception e)  
       e.printStackTrace(); 
           
   gatt.disconnect(); 

此外,您可以使用隐藏方法“刷新”刷新 gatt 服务。最初刷新方法是用于更新 gatt 服务,但在某些意外断开连接的情况下,您可能需要刷新才能正确连接您的 gatt 服务。

How to programmatically force bluetooth low energy service discovery on Android without using cache

【讨论】:

【参考方案2】:

我的测试表明,这是 Android 蓝牙堆栈更普遍的问题,GATT 连接失败率约为 20%,而 ios 上仅为 2%。可以看我的详细测试结果here

部分问题是 Android BLE 链接监督超时在 Android 4.3-9 中被硬编码为 20 秒(在 Android 10 上为 5 秒,在 iOS 上为 750 毫秒),因此如果连接丢失,大多数 Android设备将在 20 秒内以静默方式重新连接失败。

但是长链接监督超时仍然不能解释第一次连接尝试的高失败率,或者短时间后连接丢失。

我发现不同的 BLE 外设在以相同的 Android 设备作为中心设备的情况下,GATT 连接失败率有很大差异。我的办公桌上有一台设备,我的 Google Pixel 3a 将以接近 100% 的速度成功连接,并保持连接数小时。我有另外两个外围设备,它们的连接失败率接近 20%,并且连接不能保持超过 15 秒。

【讨论】:

以上是关于Android 6.0 Marshmallow BLE 连接问题的主要内容,如果未能解决你的问题,请参考以下文章

Android 6.0 (MarshMallow) 上的 HttpURLConnnection 请求失败

如何在 Android 6.0 Marshmallow 中访问相机?

如何以编程方式打开 Android 6.0 (Marshmallow) 上特定应用的权限屏幕?

Android 6.0 Marshmallow BLE 连接问题

何时在运行时请求 Android Marshmallow 6.0 的权限?

在 Android 6.0 Marshmallow (API 23) 上不推荐使用 getColor(int id)