Android 8+ 上的后台扫描

Background Scanning on Android 8+

这个问题可能已经有了答案,但我们希望得到明确的确认。

目前,我们在业务中使用专有信标作为 iBeacon,我们遇到了大多数人在后台扫描时遇到的同样问题,我们求助于我们的提供商,他们告诉我们他们知道这个问题,但还没有能够修复它以进行后台扫描。

我们发现 David Young blog post 决定试一试我们发现了两个障碍物

  1. 我们无法从我们从广播接收器中的扫描结果中获得的 ScanRecord 数据中获取信标 ID(请参阅下面的代码)

  2. 我们仍然无法在后台连续扫描,并且定期扫描不适合我们的用例。

    ArrayList scanResults = intent.getParcelableArrayListExtra(BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT); ScanRecord 记录 = scanResults.get(0).getScanRecord();

我们找到了解决此问题的方法,方法是在服务实例中使用 Google Awareness Fence API and starting the service in charge of scanning as a foreground service using startForegroundService to start the service and then call startInForeground() 触发后台扫描,以显示持续通知,指示我们在 "background" 中执行的操作,此方法具有对于我们的用例来说效果很好,但它如何以显示该通知的成本来实现,这不会创造良好的用户体验。

我们想知道是否有人为这个问题找到了更好的解决方案,因为从 google 文档来看,后台扫描是我们肯定无法再做的事情了

您对 Android 8+ 长期蓝牙扫描的三个选项的总结基本上是正确的。如果没有持久通知,您就无法进行持续的后台扫描。您可以:

  1. 使用 JobScheduler 进行定期扫描。您最多可以每 15 分钟扫描 10 分钟。
  2. 运行 一种前台服务,可以永远保持持续扫描,但代价是持续通知用户您的应用程序处于活动状态并正在使用电池。
  3. 使用基于意图的扫描始终在蓝牙广告中寻找字节模式。这仅适用于 Android 8+,但如果操作正确,您当然可以从数据包中解析出信标标识符。

默认情况下,开源 Android Beacon 库在 Android 8+ 上同时使用选项 (1) 和 (2)。当定期扫描未处于活动状态时,它使用基于意图的扫描选项,这实际上允许您始终检测新的信标。

目前尚不清楚为什么您无法从通过基于意图的扫描收到的数据包中解析出标识符,因为上述库已经在几个 Android 8 设备上成功地做到了这一点。也许过滤器被设置为广泛所以它匹配不包含您期望的标识符的数据包?

您可以在库中查看有效的代码 here:

 ArrayList<ScanResult> scanResults = intent.getParcelableArrayListExtra(BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT);

上面的代码与您使用的相同。解码发生 here.

从第二个link可以看出,后台检测不仅解析来自Intent的记录,还会使库使用JobScheduler来调度一个constant scan(简述)。因此,即使由于某种原因您的设备没有成功传递基于 Intent 的扫描的扫描结果,在接收到 Intent 后使用 JobScheduler 启动临时扫描的技术将捕获并解码后续广告,如果信标出现在附近并定期传输。