Android蓝牙。如何通过原始广告数据过滤扫描

Android BLE. How to filter Scan by raw advertising data

我必须构建一个 Android 应用程序来读取一种设备上的信息,该设备仅在过滤时显示在扫描中(一般扫描不会显示)。该设备类似于信标,因此它只公布数据,其中包含我想要的广告信息(不可连接)。 制造商给我的过滤器是原始数据。即:

0x02010612435542

我无法按名称过滤它,因为设备不会公布它的名称。我也无法通过 MAC Address 做到这一点,因为该应用程序之前不会知道设备的地址(它将是许多此类设备)。

nrfConnect 应用程序做得很好,如下所示:

应用程序上的过滤器名称是:

Filter by raw advertising data

并且,过滤后,设备在应用程序中的显示方式如下:

所以,事情是这样的。我无法按名称或 MAC Address.

进行过滤

Java(android/ble 标准库)中用于过滤的其他选项是:

    ScanFilter scanFilter1 = new ScanFilter.Builder().setManufacturerData(manufacturerId, manufacturerData).build();
    ScanFilter scanFilter2 = new ScanFilter.Builder().setServiceData(serviceDataUuid, serviceData).build();
    ScanFilter scanFilter2 = new ScanFilter.Builder().setServiceUuid(serviceUuid).build();

我拿到了厂商提供的UUID。这是

B54ADC00-67F9-11D9-9669-0800200C9A66

但是,正如制造商所说,UUID 用于扫描 iOS,不适用于 Android(已测试,确实如此)。

所以,我还剩下上面 scanFilters 的 2 个选项。

我有这样的知识:"The manufacturer data is advertised within the raw advertising data, which can be found via nrfConnect App. And the first two bytes of the manufacturer data, is the manufacturer ID, to use with the setManufacturerData() filter"。 我什至能够检索原始制造商广告数据(使用 setDeviceAddress() 过滤器(用于测试,使用测试设备,因为正如我所说,应用程序以前不知道 MAC 地址),我得到了一些东西像这样:

0X020106124355420000080390BECB49400400CB500CF

抱歉问了这么长的问题,但我已尽我所能使其尽可能完整。

我已尽我所能使用那些 scanFilter 方法,但无法使其正常工作。

有人知道如何实现吗?我为此疯狂了一个多月。

提前致谢!

我终于找到了解决办法。它没有回答有关通过原始广告数据进行过滤扫描的问题,但我可以扫描我需要的设备。这就是我所做的:

首先,我按名称制作了一个过滤器。虽然设备没有名称,但我按名称过滤以扫描 name == null.

的设备
private List<ScanFilter> scanFilters() {
    List<ScanFilter> list = new ArrayList<ScanFilter>();

    ScanFilter scanFilterName = new ScanFilter.Builder().setDeviceName(null).build();

    list.add(scanFilterName);

    return list;
}

在那之后,我需要第二个过滤器(它不在上面的 scanFilters() 方法上,它在 scanResult 上)因为它返回给我大量的设备,而那个过滤器是由 MAC 地址前缀(我的设备是一样的)。

private Set<String> btDevice = new LinkedHashSet<String>();

private ScanCallback scanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {

        BluetoothDevice device = result.getDevice();

        ScanRecord record = result.getScanRecord();
        byte[] dataByteArray = record.getBytes();

        if (device.getAddress().startsWith("F8:36:9B")) {
            btDevice.add(device.getAddress());
        }
    }
};

最后,我只扫描了我需要的设备。我仍然想知道主要问题,如果有人对此有解决方案,请随时回答。谢谢!

我用两种方法终于弄明白了

  1. 使用 ScanCallback

             ScanCallback  mScanCallback = new ScanCallback() {
                         @Override
                         public void onScanResult(int callbackType, ScanResult result) {
    
    
                             byte[] scanRecord = result.getScanRecord().getBytes();
                             //scanRecord will give you the raw advertisement data given by the device in byte array.
    
                         }
    
                         @Override
                         public void onBatchScanResults(List<ScanResult> results) {
                             for (ScanResult sr : results) {
                                //
                             }
                         }
    
                         @Override
                         public void onScanFailed(int errorCode) {
                            //
                         }
                     };
    
  2. 使用 LeScanCallback

          BluetoothAdapter.LeScanCallback mLeScanCallback =
                     new BluetoothAdapter.LeScanCallback() {
                         @Override
                         public void onLeScan(final BluetoothDevice device, int rssi,
                                              byte[] scanRecord) {
    
          //scanRecord will give you the raw advertisement data given by the device in byte array.
    
                         }
                     };
    

您可以从这个字节数组中筛选出您想要的设备。

例如:

为了仅找出心率监测设备,我已将 scanRecord 字节数组转换为字符串,然后检查其中是否出现“0d 18”。

如果设备原始广告数据包含“0d 18”字符串,则它是心率监测器,否则不是。

如果有人还需要帮助,请告诉我