检测 BLE 设备是否可连接 Android

Detecting whether a BLE device is connectable on Android

我正在做一个配置信标的项目。通电一定时间后,信标将变得不可配置,直到它重新通电。为了显示可配置信标的列表,我正在查看某些特征(蓝牙设备名称、广告数据包中的某些制造商数据)。我还需要知道它是否是 "connectable",我。 e.如果设备的 BLE 广告数据包中的 PDU 类型表明它是可连接的。我在 Android 4.X 和 5.X 中搜索了 Android Bluetooth 类 high 和 low 并且找不到任何可以说明的东西我这个信息。

我意识到确定信标可连接性的一种方法是连接到它,例如。例如:device.connectGatt(...)。但是,我看到有时需要两分钟以上才能回调 onConnectionStateChange 返回 STATE_DISCONNECTED。此外,一个环境中可能有许多这样的信标,连接到每个 可能 可配置的信标将是低效的。

可以在 CBCentralManagerDelegate 回调方法 centralManager:didDiscoverPeripheral:advertisementData:RSSICBAdvertisementDataIsConnectable 键下的 advertisementData 字典中找到该属性的 iOS 等价物。

所以,问题是:Android 上有没有办法根据广告数据或扫描结果确定 BLE 设备是否 "connectable" 或...?

更新: AS Android O SDK 中的最终 API,ScanResult class(本身添加为 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

问题出在 Anroid 8.0 之前的设备上,Android 扫描 API 不允许您访问这些 header。您从 Android 4.x:

的回调中得到了三个字段
onLeScan(BluetoothDevice device, rssi, byte[] scan data)

扫描数据字节数组在 上述header 字节后 开始。从我所看到的 BluetoothDevice 定义来看,字段或方法的 none 告诉您它是否是可连接的广告 - class 只是蓝牙的容器 mac 地址和在蓝牙堆栈上执行函数的方法。 IBluetooth.aidl 中没有方法可以获取此标志,这是蓝牙堆栈的私有接口(以及 BluetoothDevice 调用以获取其信息的方法)。

在 Android 8.0 之前,此信息似乎没有从 BlueDroid 堆栈向上传递到 Java 层。

应该可以,因为 Nordic 的 nRF Master Control Panel 可以做到这一点。

经过一番挖掘,我想我知道它是如何做到这一点的。不过,我不确定这样做是否正确。

我尝试使用 LE Advertiser 并将设备设置为可连接。在 Nordic 应用程序中,根据在 scanResult.getFlags().

处找到的字节,将设备设置为可连接

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

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