如何实现 JobScheduler 在后台扫描蓝牙信标?
How to implement JobScheduler to scan for Bluetooth beacons in the background?
我正在编写一个应用程序,当应用程序处于前台和后台时扫描蓝牙信标。我弄清楚了前景部分,但我不知道如何处理背景部分,尤其是在 android 8.0 及更高版本中,系统不允许应用程序 运行 超过 15 分钟背景。
该应用需要扫描信标并获取其 mac 地址和 UUID。此外,它应该得到扫描响应,因为那里有一些我需要解码和保存的信息。我已经使用指南 here 实现了使用 BluetoothLeScanner 的前台扫描。至于背景,我尝试将扫描模式更改为 LOW_POWER,但 OS 会在大约 15 分钟后终止应用程序。请注意,我不想要一个不断通知的前台服务,我可以只扫描 运行ning 间隔约 15 分钟。
许多人建议使用 Android Beacon 库,但我找不到我们使用的信标类型 Kontakt Beacon Pro BP16-3 所需的 beaconLayout,因此 Beacon 库无法检测到它们。
我需要的信标信息包括唯一 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 应用程序确认了电池电量,所以我确信它是正确的。
当我使用 Beacon 库时,我找不到一种简单的方法来获取扫描响应的解析版本。相反,我必须使用 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 和电池方面省去很多麻烦。但是,可靠地实施后台扫描会困难得多。因此,有没有办法结合两者的优点,让 bacon 库解析唯一 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
提前致谢。
您无法仅通过扫描广告来读取 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 不会公布其电池电量。要获取它,您必须单独连接到 Service UUID = 0x1805 的 GATT 服务,然后读取 Characteristic UUID = 0x2a19 的特征值。这将 return 一个介于 0-100 之间的值,指示电池的百分比级别。
您可以在 Kontakt.io 的 "Other BLE Scanners" 部分 here.
中查看有关如何访问它的详细信息
好的,所以这并没有告诉您如何编写代码来读取该值。为此,您需要学习蓝牙 LE GATT 编程的基础知识,这需要一点学习。一个好的起点是 here. 您需要编写几个步骤:
- 扫描设备(Android Beacon 库使用其 Ranging API 为您完成此部分,为您提供
String macAddress = beacon.getBluetoothAddress();
中的设备 MAC 地址)
- 连接到设备。如果您已使用该库进行发现,则可以获得对设备的引用并使用
bluetoothAdapter.getRemoteDevice(macAddress).connectGatt(...)
连接到它
- 发现服务
- 在上述步骤的服务列表中查找 0x1805 服务 uuid。
- 从上面发现已发现服务的特征
- 在上述步骤的特征列表中查找 0x2a19 特征 uuid。
- 读取上述发现特征的值。
使用附近信标的蓝牙 MAC 地址字符串的存储副本,可以将上述所有内容放入每 15 分钟 运行 的预定作业中。
我知道这并不容易。我希望我能给你几行代码来获得电池电量,但不幸的是它不能那样工作。欢迎来到蓝牙 LE GATT 编程世界!
根据链接的 Kontakt.io 文档,电池电量也可在扫描响应中找到。 (注意:当您检测到信标数据包时,扫描响应并非 总是 可用,但它通常可用 - 它由 Android OS 和当收到扫描响应时与扫描数据合并。)在原始 Android 扫描结果 bye 数组中,扫描响应简单地附加在常规扫描数据的末尾。
当使用Android Beacon 库时,扫描响应也是可用的,Android 操作系统获取扫描响应并将其存储在BluetoothDevice#name 字段中。 (参见 here)。 Android Beacon 库在解析信标时,将该字段复制到 Beacon#name 字段中。因此,如果您可以解析信标并且设备检测到扫描响应,则该信息将以字符串形式提供给您。
这里有两个障碍:
您的 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)。它有一个 0x0102 的 16 位服务 UUID,它对应于 standard or custom 16 位 UUID 的蓝牙 SIG 列表中的任何内容。你的猜测和我的一样好!
BluetoothDevice#name 或 Beacon#name 将是一个字符串。您需要将其转换为字节,然后按照 Kontakt.io 在其扫描响应文档中的描述解析出电池电量。
我正在编写一个应用程序,当应用程序处于前台和后台时扫描蓝牙信标。我弄清楚了前景部分,但我不知道如何处理背景部分,尤其是在 android 8.0 及更高版本中,系统不允许应用程序 运行 超过 15 分钟背景。
该应用需要扫描信标并获取其 mac 地址和 UUID。此外,它应该得到扫描响应,因为那里有一些我需要解码和保存的信息。我已经使用指南 here 实现了使用 BluetoothLeScanner 的前台扫描。至于背景,我尝试将扫描模式更改为 LOW_POWER,但 OS 会在大约 15 分钟后终止应用程序。请注意,我不想要一个不断通知的前台服务,我可以只扫描 运行ning 间隔约 15 分钟。
许多人建议使用 Android Beacon 库,但我找不到我们使用的信标类型 Kontakt Beacon Pro BP16-3 所需的 beaconLayout,因此 Beacon 库无法检测到它们。
我需要的信标信息包括唯一 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 应用程序确认了电池电量,所以我确信它是正确的。
当我使用 Beacon 库时,我找不到一种简单的方法来获取扫描响应的解析版本。相反,我必须使用 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 和电池方面省去很多麻烦。但是,可靠地实施后台扫描会困难得多。因此,有没有办法结合两者的优点,让 bacon 库解析唯一 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
提前致谢。
您无法仅通过扫描广告来读取 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 不会公布其电池电量。要获取它,您必须单独连接到 Service UUID = 0x1805 的 GATT 服务,然后读取 Characteristic UUID = 0x2a19 的特征值。这将 return 一个介于 0-100 之间的值,指示电池的百分比级别。
您可以在 Kontakt.io 的 "Other BLE Scanners" 部分 here.
中查看有关如何访问它的详细信息好的,所以这并没有告诉您如何编写代码来读取该值。为此,您需要学习蓝牙 LE GATT 编程的基础知识,这需要一点学习。一个好的起点是 here. 您需要编写几个步骤:
- 扫描设备(Android Beacon 库使用其 Ranging API 为您完成此部分,为您提供
String macAddress = beacon.getBluetoothAddress();
中的设备 MAC 地址) - 连接到设备。如果您已使用该库进行发现,则可以获得对设备的引用并使用
bluetoothAdapter.getRemoteDevice(macAddress).connectGatt(...)
连接到它
- 发现服务
- 在上述步骤的服务列表中查找 0x1805 服务 uuid。
- 从上面发现已发现服务的特征
- 在上述步骤的特征列表中查找 0x2a19 特征 uuid。
- 读取上述发现特征的值。
使用附近信标的蓝牙 MAC 地址字符串的存储副本,可以将上述所有内容放入每 15 分钟 运行 的预定作业中。
我知道这并不容易。我希望我能给你几行代码来获得电池电量,但不幸的是它不能那样工作。欢迎来到蓝牙 LE GATT 编程世界!
根据链接的 Kontakt.io 文档,电池电量也可在扫描响应中找到。 (注意:当您检测到信标数据包时,扫描响应并非 总是 可用,但它通常可用 - 它由 Android OS 和当收到扫描响应时与扫描数据合并。)在原始 Android 扫描结果 bye 数组中,扫描响应简单地附加在常规扫描数据的末尾。
当使用Android Beacon 库时,扫描响应也是可用的,Android 操作系统获取扫描响应并将其存储在BluetoothDevice#name 字段中。 (参见 here)。 Android Beacon 库在解析信标时,将该字段复制到 Beacon#name 字段中。因此,如果您可以解析信标并且设备检测到扫描响应,则该信息将以字符串形式提供给您。
这里有两个障碍:
您的 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)。它有一个 0x0102 的 16 位服务 UUID,它对应于 standard or custom 16 位 UUID 的蓝牙 SIG 列表中的任何内容。你的猜测和我的一样好!BluetoothDevice#name 或 Beacon#name 将是一个字符串。您需要将其转换为字节,然后按照 Kontakt.io 在其扫描响应文档中的描述解析出电池电量。