如何实现JobScheduler在后台扫描蓝牙信标?

时间:2019-03-31 21:41:16

标签: android bluetooth-lowenergy ibeacon android-bluetooth ibeacon-android

我正在编写一个应用程序,当该应用程序位于前景和背景之间时,它将扫描蓝牙信标。我已经找到了前台部分,但是我不知道该为后台部分做什么,尤其是在android 8.0及更高版本中,系统不允许应用程序在后台运行超过15分钟。

应用程序需要扫描信标并获取其Mac地址和UUID。另外,它应该获得扫描响应,因为那里需要解码和保存一些信息。我已经使用指南here来使用BluetoothLeScanner进行前景扫描。至于背景,我尝试将扫描模式更改为LOW_POWER,但操作系统在15分钟左右后将其终止。请注意,我不希望前台服务具有恒定的通知,并且我认为扫描仅间隔约15分钟运行就可以了。

许多人建议使用Android信标库,但我找不到所用信标类型所需的beaconLayout,即Kontakt Beacon Pro BP16-3,因此信标库未检测到它们。

我从信标中需要的信息包括唯一的ID和电池百分比。有关它们在扫描响应中的位置的详细信息,请参见[here](https://support.kontakt.io/hc/en-gb/articles/206294004-How-to-check-the-battery-level-on-your-beacons)。

对于在后台搜索信标的代码提供的任何帮助(在适用于Android 6.0及更高版本的任何Android版本上运行),或者将信标库与上述信标配合使用的帮助,我将不胜感激。

编辑:扫描响应中的唯一ID和蓝牙

当我使用BLEScanner扫描信标时,可以使用ScanResult :: getScanRecord()获取scanRecord对象。然后,我使用getServiceData()方法获取一个字节数组,其前4个字节代表ASCII中的唯一ID,后两个字节是ASCII中的固件版本,最后一个字节是十六进制的电池百分比。我什至通过Kontakt官方应用程序确认了电池电量,因此我确定它是正确的。

当我使用信标库时,我找不到一种简单的方法来获取已解析的扫描响应版本。相反,我必须使用NonBeaconLeScanCallback来获取字节数组。然后,字节数组结果为

[2, 1, 6, 26, -1, 76, 0, 2, 21, -9, -126, 109, -90, 79, -94, 78, -104, -128, 36, -68, 91, 113, -32, -119, 62, -91, 68, 124, 56, -77, 8, 9, 75, 111, 110, 116, 97, 107, 116, 2, 10, -12, 10, 22, 13, -48, 68, 106, 69, 77, 52, 50, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0].

似乎索引46-49中的字节表示ASCII中的唯一ID,在这种情况下为“ DjEM”。此外,索引52的字节是电池百分比,以十进制表示;在这种情况下为68。

看来,通过使用BLE扫描器,我在解析唯一ID和电池方面可以省去很多麻烦。但是,要可靠地执行后台扫描将更加困难。因此,是否有一种方法可以将两者的优点结合起来,并获得培根库来解析唯一ID和电池百分比?

EDIT2:无法识别我的信标时的信标库消息

即使我同时使用iBeacon和EddyStone信标布局,信标库仍无法检测到我的信标。它在logcat中打印以下内容:

 processing pdu type 16: 0201060d166afe0206010a64f456425a4d08094b6f6e74616b74000000000000000000000000000000000000000000000000000000000000000000000000 with startIndex: 5, endIndex: 16
This is not a matching Beacon advertisement. (Was expecting 02 15.  The bytes I see are: 0201060d166afe0206010a64f456425a4d08094b6f6e74616b74000000000000000000000000000000000000000000000000000000000000000000000000
Ignoring pdu type 01

谢谢。

2 个答案:

答案 0 :(得分:1)

仅通过扫描广告,您无法读取Kontakt.io信标的电池电量。您必须使用板载GATT服务连接到它(有关更多信息,请参见下文。)

对于在后台和前台进行常规扫描,您当然可以使用Android Beacon库。您可能要使用iBeacon布局:

        mBeaconManager.getBeaconParsers().add(new BeaconParser().
                setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));

但是,尽管上面的方法可以检测到您的信标,但不会告诉您电池电量。这是因为Kontakt不会公布其电池电量。要获取它,您必须单独连接到服务UUID = 0x1805的GATT服务,然后读取特征UUID = 0x2a19的特征值。这将返回0-100之间的值,指示电池的百分比水平。

您可以在Kontakt.io的“其他BLE扫描器”部分here中查看有关如何访问此方法的详细信息。

好,所以这不会告诉您如何编写代码以读取该值。为此,您需要学习Bluetooth LE GATT编程的基础知识,这需要一些学习。 here.是一个不错的起点,您需要编写一些步骤:

  1. 扫描设备(Android信标库使用其测距API为您完成此部分,并在String macAddress = beacon.getBluetoothAddress();中为您提供设备MAC地址)
  2. 连接到设备。如果您已使用该库进行发现,则可以获取对该设备的引用并使用bluetoothAdapter.getRemoteDevice(macAddress).connectGatt(...)
  3. 连接到该设备
  4. 发现服务
  5. 在上述步骤的服务列表中查找0x1805服务uuid​​。
  6. 从上方发现所发现服务的特征
  7. 在上述步骤的特征列表中查找0x2a19特征uuid。
  8. 读取上面发现的特征的值。

上述所有操作都可以使用附近信标的蓝牙MAC地址字符串的已存储副本放入计划的作业中,每15分钟运行一次。

我知道这并不容易。我希望我可以给您几行代码来获取电池电量,但不幸的是,它不能那样工作。欢迎来到蓝牙LE GATT编程世界!

答案 1 :(得分:1)

根据链接的Kontakt.io文档,电池电量在扫描响应中也可用。 (请注意:当您检测到信标包时,扫描响应始终不可用,但它经常可用-由Android操作系统提供,并在扫描响应获得时与扫描数据合并在原始Android扫描结果bye数组中,只需在常规扫描数据的末尾附加扫描响应即可。

使用Android信标库时,扫描响应也可用,Android操作系统获取扫描响应并将其存储在BluetoothDevice#name字段中。 (请参见here)。 Android Beacon库在解析信标时,会将其复制到Beacon#name字段中。因此,如果您可以解析信标并且设备检测到扫描响应,则该信息将以字符串形式提供给您。

这里有两个障碍:

  1. 您的Kontakt.io信标似乎没有在宣传任何实际上是信标广告的东西。您可能需要对其进行配置,以发布iBeacon格式或Eddystone-UID格式。完成此操作并使用该布局配置Android Beacon库后,它将检测到它。请注意,显示的字节:processing pdu type 16: 0201060d166afe0206010a64f456425a4d08094b6f6e74616b74000000000000000000000000000000000000000000000000000000000000000000000000 with startIndex: 5, endIndex: 16 This is not a matching Beacon advertisement.与iBeacon或Eddystone不对应。这似乎是某种专有的16位GATT服务广告(AD类型0x16)。它的16位服务UUID为0x0102,与standardcustom 16位UUID的Bluetooth SIG列表中的任何内容都不对应。您的猜测与我的猜测一样好!

  2. BluetoothDevice#名称或Beacon#名称将为字符串。您将需要将其转换为字节,然后按照Kontakt.io在其扫描响应文档中所述解析电池电量。