如何实现作业计划程序以在后台扫描蓝牙信标.



我正在编写一个应用程序,当应用程序处于前台和后台时,该应用程序会扫描蓝牙信标。我已经弄清楚了前景部分,但我不知道该怎么做后台部分,尤其是在 android 8.0 及更高版本中,系统不允许应用程序在后台运行超过 15 分钟。

该应用程序需要扫描信标并获取其 MAC 地址和 UUID。此外,它应该获得扫描响应,因为那里有一些我需要解码和保存的信息。我在这里使用指南使用蓝牙LeScanner实现前台扫描。至于后台,我尝试将扫描模式更改为LOW_POWER,但操作系统在大约 15 分钟后杀死了该应用程序。请注意,我不想要带有持续通知的前台服务,并且我可以接受扫描仅以~15分钟的间隔运行。

许多人建议使用 Android 信标库, 但我找不到我们使用的信标类型所需的信标布局, Kontakt Beacon Pro BP16-3, 所以信标库没有检测到它们.

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

我将不胜感激任何帮助编写代码以在后台搜索信标,这些信标可以在 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 和电池百分比?

编辑2:无法识别我的信标时信标库消息

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

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

提前谢谢。

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

对于背景和前台的一般扫描,您当然可以使用Android信标库。 您可能希望使用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扫描仪"部分查看有关如何访问的详细信息。

好的,所以这不会告诉你如何编写代码来读取该值。 为此,您需要学习蓝牙 LE GATT 编程的基础知识,这需要一些学习。 一个好的起点就在这里。 您需要编写几个步骤:

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

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

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

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

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

这里有两个障碍:

  1. 您的 Kontakt.io 信标似乎没有在宣传任何实际上是信标广告的东西. 您可能需要将其配置为通告iBeacon格式或Eddystone-UID格式。 完成此操作并使用该布局配置 Android 信标库后, 它将检测到它. 请注意,显示的字节: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,与标准或自定义 16 位 UUID 的蓝牙 SIG 列表中的任何内容都不对应。 你的猜测和我的一样好!

  2. 蓝牙设备#名称或信标#名称将是一个字符串。 您需要将其转换为字节,然后按照 Kontakt.io 扫描响应文档中的说明解析电池电量。

最新更新