在Android上检测BLE设备是否可连接

11
我正在为配置信标的项目工作。在开机后一定时间后,信标会变得不可配置,直到重新上电为止。为了显示可配置的信标列表,我查看了某些特征(蓝牙设备名称、广告数据中的某些制造商数据)。 我还需要知道它是否“可连接”,即BLE广告数据包中的PDU类型是否表明它是可连接的。我已经在Android 4.X和5.X中高低搜索了Android Bluetooth类,但没有找到任何可以提供此信息的东西。
我意识到确定信标可连接性的一种方法是连接到它,例如:device.connectGatt(...)。然而,有时需要超过两分钟才能通过onConnectionStateChange回调返回STATE_DISCONNECTED。此外,在环境中可能有许多这些信标,连接到每个可能可配置的信标将效率低下。
在iOS中,可以在CBAdvertisementDataIsConnectable键下的advertisementData字典中找到此属性的等效项。在CBCentralManagerDelegate回调方法centralManager:didDiscoverPeripheral:advertisementData:RSSI中。
因此,问题是:在Android上是否有一种方法可以从广告数据或扫描结果等中确定BLE设备是否“可连接”?
2个回答

14
更新:在Android O SDK的最终API中,ScanResult类(自Android 5.0引入)现在具有isConnectable()方法。仅在Android 8.0+上才能检测可连接的广告。有关更多信息,请参见此处:https://developer.android.com/reference/android/bluetooth/le/ScanResult.html#isConnectable() 很遗憾,在Android 8.0之前是不可能检测到可连接广告的。
可连接广告是由PDU Header字节0确定的。您可以在下面的示例结构中看到这一点:
d6 be 89 8e # Access address for advertising data (this is always the same fixed value)
40 # Advertising Channel PDU Header byte 0.  Contains: (type = 0), (tx add = 1), (rx add = 0)
24 # Advertising Channel PDU Header byte 1.  Contains:  (length = total bytes of the advertising payload + 6 bytes for the BLE mac address.)
05 a2 17 6e 3d 71 # Bluetooth Mac

问题出现在Android 8.0之前的设备上,Android扫描API无法访问这些标头。在Android 4.x中从回调中仅获取三个字段:

onLeScan(BluetoothDevice device, rssi, byte[] scan data)
扫描数据字节数组在上述头字节之后开始。从我所看到的 BluetoothDevice 定义中,没有任何字段或方法可以告诉您它是否是可连接广告 - 该类只是蓝牙 Mac 地址的容器,具有在蓝牙堆栈上执行功能的方法。而且,在蓝牙堆栈的私有接口 IBluetooth.aidl 中(以及 BluetoothDevice 调用以获取其信息的内容)没有任何方法可以获取此标志。似乎在 Android 8.0 之前的 BlueDroid 堆栈中,这些信息不会传递到 Java 层。

鉴于你的断言与我的发现相吻合,我认为这里的答案是没有答案。 :-( - mharper
3
从Android O版本开始,这是现在可以实现的。 - davidgyoung

4

由于Nordic的nRF主控面板可以实现此功能,因此应该是可能的。

经过一些挖掘,我认为我知道它是如何做到的。不过我不确定这是否是正确的方法。

我尝试使用LE Advertiser并将设备设置为可连接状态。在Nordic应用程序中,设备的可连接状态取决于在scanResult.getFlags()中找到的字节。

我发现这段代码适用于我的设备:

int flags = scanResult.getScanRecord().getAdvertiseFlags();
if ((flags & 2) == 2) {
  //connectable
}

有趣。ScanRecord对象是在Android 5.0中添加的。你知道nRF Master Control Panel只在Android 5+设备上执行这个操作吗?如果它可以在Android 4.x设备上工作,那么肯定有另一种方法。 - davidgyoung
1
我无法重现这些结果。我在 Nexus 9 上使用 Android 5 BLE API 扫描 RadBeacon USB 进行了测试。我将 RadBeacon 设置为可连接模式(使用 TI CC2540 扫描仪验证),Android 的 scanResult.getScanRecord().getAdvertiseFlags() 返回值为 6。然后,我将 RadBeacon USB 更改为不可连接模式(再次使用扫描仪进行验证),scanResult.getScanRecord().getAdvertiseFlags() 仍然返回 6。为了确保这不仅仅是缓存问题,我关闭/打开了蓝牙,然后插入信标。它仍然返回 6。 - davidgyoung
根据我的经验,关于"可连接"标志似乎存在一些分歧,而规范并不完全清楚(或者我只是没有找到完整的定义)。我曾经使用CSR信标,在其中,如果将LE可发现模式标志设置为true,则它也会显示为可连接;而在使用Bluegiga信标时,可发现模式标志对可连接标志没有影响。如果您尝试使用Nordic应用程序,您可能会发现您的RadBeacon显示为可连接。是的,我相信Nordic应用程序适用于<5.0,因此一定有另一种方法。 - user3934907
2
我对此进行了更多的研究,并发现了这个标志值返回的内容。它是广告中Flags AD块的字节值,这并不告诉您设备是否可连接。它告诉您设备是否可被发现,这是完全不同的事情。位值如下:位0 LE有限发现模式,位1 LE通用发现模式,位2 BR/EDR不支持,位3控制器同时支持LE和BR/EDR到同一设备,位4主机同时支持LE和BR/EDR到同一设备。 - davidgyoung
我可以确认,即使对于已知会广播不可连接的设备,nRF应用程序在Android 6.0.1上仍显示连接按钮。这是使用nRF应用程序版本4.0.1。 - PVS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接