ScanFilter android 中的 uuid 导致信标检测失败

问题描述 投票:0回答:1

我们在 Android 前台服务中使用 ScanFilter 来扫描信标。过滤器包括服务 UUID。当我们删除服务UUID时,我们可以检测具有指定uuid的信标。但是,当我们包含服务 UUID 时,信标检测失败。

private var scanFilter: ScanFilter = ScanFilter.Builder()
.setServiceUuid(ParcelUuid(UUID.fromString("0000feab-0000-1000-8000-00805f9b34fb"))) // Filter by Service UUID
.build()

如果我们删除了服务 UUID 过滤器,我们将得到以下我们想要在

onScanResult
回调中检测到的信标结果

ScanResult{device=CF:63:4B:5D:E1:F9, scanRecord=ScanRecord [mAdvertiseFlags=6, mServiceUuids=null, mServiceSolicitationUuids=[], mManufacturerSpecificData={}, mServiceData={0000feab-0000-1000-8000-00805f9b34fb=[64, 0, 2, 11, -30, 0, 1, -49, 99, 75, 93, -31, -7, 48, 10]}, mTxPowerLevel=0, mDeviceName=0001, mTransportBlocks=[]], rssi=-71, timestampNanos=40980732284950, eventType=27, primaryPhy=1, secondaryPhy=0, advertisingSid=255, txPower=127, periodicAdvertisingInterval=0}

在上面的结果中

mServiceUuids
为空,我认为这是问题所在,也许我正在检测的信标不是广播服务uuid,我可以基于
mServiceData
应用过滤器,如下所示:

  private val beaconUuid: ParcelUuid = ParcelUuid.fromString("0000feab-0000-1000-8000-00805f9b34fb")
private var serviceData: ByteArray = byteArrayOf(64, 0) // This is the beginning of the service data
private var serviceDataMask: ByteArray = byteArrayOf(-1, -1) // This mask means match both bytes exactly

private var scanFilter: ScanFilter = ScanFilter.Builder()
    .setServiceData(beaconUuid, serviceData, serviceDataMask)  // Filter by Service Data
    .build()

我成功使用

mServiceData
和当前本机
BluethoothAdapter
过滤信标。但是,我需要切换到 AltBeacon 库以实现三星设备兼容性。当三星设备离线时,AltBeacon 基于
mServiceUuid
进行过滤,但我找不到使用此库按
mServiceData
进行过滤的方法。有人可以建议一个解决方案吗?

android bluetooth bluetooth-lowenergy android-bluetooth altbeacon
1个回答
0
投票

Android Beacon 库不将服务数据用于其扫描过滤器。 正如目前所写的,它设置了一个扫描过滤器,其中仅包含服务广告信标格式(如 Eddystone)的 ServiceUuid。 (对于 iBeacon 和 AltBeacon 等制造商广告,它会设置一个与制造商数据中的第一个字节匹配的扫描过滤器。)

执行此操作的库代码位于 ScanFitlerUtils 类此处。正如你所看到的,它只在过滤器中设置 UUID。

ScanFilter.Builder builder = new ScanFilter.Builder();
if (sfd.serviceUuid != null) {
   // Use a 16 bit service UUID in a 128 bit form
   String serviceUuidString = String.format("0000%04X-0000-1000-8000-00805f9b34fb", sfd.serviceUuid);
   String serviceUuidMaskString = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF";
   ParcelUuid parcelUuid = ParcelUuid.fromString(serviceUuidString);
   ParcelUuid parcelUuidMask = ParcelUuid.fromString(serviceUuidMaskString);
   if (LogManager.isVerboseLoggingEnabled()) {
     LogManager.d(TAG, "making scan filter for service: "+serviceUuidString+" "+parcelUuid);
     LogManager.d(TAG, "making scan filter with service mask: "+serviceUuidMaskString+" "+parcelUuidMask);
   }
   builder.setServiceUuid(parcelUuid, parcelUuidMask);
                    }

图书馆没有设置与服务数据匹配的扫描过滤器的唯一原因是,迄今为止,使用 Eddystone 等服务广告的常见信标格式还没有必要。

如果您知道您的 ServiceUUID,这应该足以使用库进行匹配。 您显示的示例代码也与服务数据的前两个字节匹配。 (Android Beacon 库目前不支持此功能,但可以进行增强以实现此目的。但您也许可以接受仅与 UUID 匹配的过滤器,并让库以编程方式检查前两个字节。)

根据您的示例代码,我可以看到您正在使用 FEAB 的 16 位服务 UUID。 因此,使用该库,您可以像这样设置一个 BeaconParser:

val beaconManager = BeaconManager.getInstanceForApplication(this)
beaconManager.beaconParsers.add(BeaconParser().setBeaconLayout("s:0-1=feab,m:2-3=4000,p:3-3:-41,i:4-21v"))

上面的信标解析器表达式告诉库匹配您的信标,如下所示:

  • s:0-1=feab
    使用 16 位服务 UUID FEAB 十六进制查找服务广告
  • m:2-3=4000
    仅当服务数据的前两个字节为 40 00 十六进制(十进制 64 0)时才匹配培根
  • p:3-3
    用于信标中距离估计的测量功率值的占位符(如果您关心距离估计,可以将其更改为数据包中的实际字节位置)
  • i:4-21v
    获取服务数据中的所有剩余字节并将它们视为单个信标标识符。 如果您想要多个标识符,您可以使用更复杂的表达式将这些字节拆分为多个标识符。

当三星屏幕关闭时,库将设置扫描过滤器,以匹配 FEAB 的 16 位服务 UUID。 但随后它将对检测进行后处理,以丢弃任何在服务数据中不具有 40 00 十六进制或 64 0 十进制的前两个字节的检测。

如上所示设置 BeaconParser 后,您可以使用该库来检测这些信标,并且它应该根据需要使用扫描过滤器来在屏幕关闭和后台进行检测。

© www.soinside.com 2019 - 2024. All rights reserved.