android 使用 BluetoothLeScanner 时如何过滤制造商数据?

How to filter on manufacturer data when using BluetoothLeScanner for android?

我正在使用自己的 BLE 设备。在这些设备之后收听时,我想使用 ScanFilter,所以我只得到我感兴趣的设备。我现在的解决方案是在回调内部进行过滤,但如果这种过滤可以更早地进行并根据按照规范应该是可能的。我正在尝试过滤制造商特定数据,但我无法使其正常工作。这是我的代码:

BluetoothLeScanner bleScanner = bluetoothAdapter.getBluetoothLeScanner();
ScanFilter filter = getScanFilter();
List<ScanFilter> scanFilters = new ArrayList<>();
scanFilters.add(filter);
ScanSettings scanSettings = getScanSettings();
bleScanner.startScan(scanFilters, scanSettings, scanCallback);

这是创建过滤器和设置的函数:

private ScanSetting getScanSettings(){
    ScanSettings.Builder builder = new ScanSettings.Builder();
    builder.setReportDelay(0);
    builder.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER);
    return builder.build();
}

private ScanFilter getScanFilter(){
    ScanFilter.Builder builder = new ScanFilter.Builder();
    ByteBuffer manData = ByteBuffer.allocate(6); //The sensors only sends 6 bytes right now
    ByteBuffer manMask = ByteBuffer.allocate(6);
    manData.put(0, (byte)0x50);
    manData.put(1, (byte)0x41);
    manData.put(2, (byte)0x43);
    manData.put(3, (byte)0x4b);
    manData.put(4, (byte)0x45);
    manData.put(5, (byte)0x54);
    for(int i = 0; i < 6; i++){
        manMask.put((byte)0x01);
    }
    builder.setManufacturerData(20545, manData.array(), manMask.array()); //Is this id correct?
    return builder.build();
}

如果我不使用任何过滤器或仅具有此功能的设置:

bluetoothLeScanner.startScan(scanCallback);

我得到了我的 BLE 设备,所以我知道它们正在正确广播。我还可以打印制造商特定数据,并且可以看到它是我在过滤器中使用的 6 个相同字节。我不确定 id(.setManufacturerData 函数中的第一个参数)是否正确,因为我能找到的关于此的唯一信息来自 android 开发人员页面的以下文本 ScanFilter.Builder:

"Note the first two bytes of the manufacturer Data is the manufacturerId"

当我使用此代码并尝试在设备后进行扫描时,我什么也没得到。我在这里错过了什么?

我设法让它工作。是 manufacturerId 不正确。这不是我从前两个字节得到的 20545。相反,我发现我可以通过执行以下操作从 ScanResult(当我不使用过滤器时)获取此 ID:

ScanRecord scanRecord = scanResult.getScanRecord();
SparseArray<byte[]> manufacturerData = scanRecord.getManufacturerSpecificData();
for(int i = 0; i < manufacturerData .size(); i++){
    int manufacturerId = manufacturerData.keyAt(i);
}

通过这样做,我得到了正确的 manufacturerId,然后我可以将其放入 bleScanner.startScan 函数中。

SIG 定义 "manufacturer specific data" 以包含制造商 ID 作为前 2 个字节,后跟任何其他数据。 Android 然后通过提取前 2 个字节来确定制造商 ID,保留其余字节。如果您的广告数据包不使用制造商 ID(不推荐,但我的情况是这样),Android 的 "manufacturer data" 实际上会丢失 2 个字节。

就我而言,固件工程师需要为数据分配全部字节。因此,我最终在 Android 端得到了错误解析的制造商数据。

解决方案是将过滤器的前两个字节分隔为 ID 的整数。剩余的字节进入数据。像这样:

fun createAndroidManufacturerDataFilter(query: String): ScanFilter {
    return ScanFilter.Builder().setManufacturerData(
        convertASCIItoByteArrayToInt(query.substring(0, 2)),
        convertASCIItoByteArray(query.substring(2))
    ).build()
}