在 android 8(oreo) 上使用 altbeacon 库,后台信标扫描不工作

using altbeacon library on android 8(oreo), background beacon scan not working

我的应用使用 Altbeacon 库进行信标扫描。

我的代码在 api 级别 24(android 7) 上运行良好,但不能在 oreo(8.0.0)

上运行

起初,我的gradle设置compileSdkVersion和targetSdkVersion是26,我以为是因为这个。

所以,我参考这个**https://developer.android.com/about/versions/oreo/background.html#services**, 修复我的 gradle 设置(compileSdkVersion 25,targetSdkVersion 25)。

并在设备上安装此应用(api级别 24、26) 在 24 级设备上运行良好,但 26 级设备运行不正常。

这是我的代码。

Activity.onCreate

    Intent intent = new Intent(this, BeaconService.class);
    startService(intent);

BeaconService(Altbeacon 库)

@Override
public void onBeaconServiceConnect()
{
    final Handler h = new Handler(getApplicationContext().getMainLooper());
    Beacon[] tempBeacon = new Beacon[2];

    bm.addRangeNotifier(new RangeNotifier() {
        @Override
        public void didRangeBeaconsInRegion(final Collection beacons, final Region region) {

            if (beacons.size() > 0) {

                //call method this context

            }
            Log.d("beacon", "detect");
        }
    });

    try
    {
            bm.startRangingBeaconsInRegion(new Region("test", Identifier.parse("A1200001-EABC-9876-D001-E00000000001"), Identifier.parse("32001"), null));
    } catch (RemoteException e) {
    }
}

编辑: 检测到信标,但需要很长时间。

我看到下面的日志

03-15 18:25:02.639 2419-2419/app.eco.inulibrary D/ScanJobScheduler: 调度 ScanJob (job:208352940/app.eco.inulibrary/org.altbeacon.beacon.service.ScanJob) 到 运行 每 310000 毫秒 03-15 18:25:02.917 2419-2419/app.eco.inulibrary D/ScanJobScheduler: 调度 ScanJob (job:208352940/app.eco.inulibrary/org.altbeacon.beacon.service.ScanJob)每 300000 毫秒 运行 03-15 18:36:00.176 2419-2419/app.eco.inulibrary I/ScanJob: 运行 定期扫描作业:实例为 org.altbeacon.beacon.service.ScanJob@a6ca148 03-15 18:36:01.751 2419-3951/app.eco.inulibrary D/RangeState:添加 id1:a1200001-eabc-9876-d001-e00000000001 id2:32001 id3:2001 到现有范围:org.altbeacon.beacon.service.RangedBeacon@bf2cb74 03-15 18:36:01.968 2419-2419/app.eco.inulibrary D/Callback:尝试通过本地广播意图回调:org.altbeacon.beacon.range_notification

如何解决这个问题?

Android O 对后台服务引入了新的限制。代码中显示的 BeaconService 等服务将在应用程序切换到后台模式后不久被操作系统终止。

AndroidBeaconLibrary 已更新以解决此问题,方法是使用 Android 作业调度程序处理 Android 8+ 上的信标扫描。但要使其工作,您必须使用 BeaconManagerRegionBootsrap class 开始扫描 ,而不是启动 BeaconService直接用 Intent。这样,库将知道在 Android 8+ 和 BeaconService 早期版本上使用作业调度程序。

此外,您需要将开始扫描和初始化的代码从 Activity 移到自定义 android.app.Application class 中。这是因为 Android 8 会在后台运行时杀死你的 Activity 和应用程序,你需要在自动创建的 Android 组件中设置测距当应用程序 re-launched 在后台进行定期扫描时。

我建议您按照示例代码 在后台启动应用程序 中所述重新设置您的设置 here。该示例仅设置监控,但您可以在显示的 didDetermineStateForRegion 回调中开始测距。

最后,确保你的库版本 2.13+ 完全支持 Android 8.1 中的更改。

要详细了解 Android 8 中背景信标检测的变化,请参阅我的博客 post here.

所以我已经玩了很长时间,试图找出在后台扫描信标的最佳方法,而不用前台服务通知烦扰用户。到目前为止,这是我发现的:

  • 运行ning in the Foreground:显然我们需要运行在前台扫描才能得到任何地方。所以我使用了@davidyoung 的一些片段,并在后台服务中构建了一个 运行 的信标扫描器。我曾经在后台设置 运行 beaconManager,但是 Android 8 使它变得困难所以我切换到 运行 在前台设置它
  • 愚蠢的通知:切换到运行在前台扫描仪后,我意识到前景有多烦人服务通知是。我尝试制作一个至少看起来很酷的自定义通知,因为无论如何我的用户都会坚持使用它,但它仍然很烦人。然后我恍然大悟... 运行 屏幕关闭时在前台扫描,然后在屏幕打开时切换到后台扫描!

屏幕驱动扫描:

想了一会儿,想起Nearby对'ScreenOn'事件进行了快速扫描后,我终于得出了这个结论。我考虑过做类似的事情,但认为最好只 运行 一个前台服务,而不是希望我的扫描作业得到及时安排。

一般结构包括以下内容:

  • A BroadcastReceiver classService class here.
  • 2 次通知调用
  • 延迟处理程序

结果:

我的服务是在 MainActivity 上启动的,它启动了我的 ScannerService。我在 MainActivity(当用户打开应用程序时)的前台 onStartCommand 中将其设置为 运行 并保持 运行ning 直到他们锁定屏幕。屏幕锁定后,应用程序将进入基于屏幕 activity 的循环。

当用户解锁 phone(在 Android 7- 上)时,前台通知会立即清除,因为服务会切换到后台服务。在 Android 8 上,向用于启动前台 BeaconManager 服务的相同 ID 发送通知,然后在切换到后台设置的 2.5 秒后取消处理程序上的通知。该通知会阻止用户收到 "Background Services are Using Battery" 通知,但它足够短,可以在他们解锁屏幕之前消失。

我的测试结果:

  1. Android 奥利奥 (API >= 26) 对于奥利奥我最好的解决方案调用方法 startScan() 和 PendingIntent (BroadcastReceiver) 。小例子:

    ...
    val bluetoothManager = applicationContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager 
    val bluetoothAdapter = bluetoothManager.adapter
    bleScanner = bluetoothAdapter.getBluetoothLeScanner()
    val listOfFiters = ArrayList<ScanFilter>()
    val builder = ScanFilter.Builder()
    val filter = builder.build()
    listOfFiters.add(filter)
    
    val startScan = bleScanner?.startScan(listOfFiters, null, getPendingIntent())
    
    ...
    
    private fun getPendingIntent(): PendingIntent {
    return PendingIntent.getBroadcast(
        this, REQ_CODE,
        Intent(this.applicationContext, BeaconBLEReceiver::class.java),
        PendingIntent.FLAG_UPDATE_CURRENT)
    }
    

    清单:

    <receiver android:name=".BeaconBLEReceiver" >
        <intent-filter>
            <action android:name="BluetoothDevice.ACTION_FOUND" />
            <action android:name="BluetoothDevice.EXTRA_UUID" />
            <action android:name="BluetoothDevice.EXTRA_RSSI" />
        </intent-filter>
    </receiver>
    

这个隐含的(不在list of exceptions上,但它有效吗?)广播至少工作几个小时(华为Y6,Mate10)。重启可以通过WorkManager来解决

  1. Api <= 26 startScan() 不支持 PendingIntent - BroadcastReceiver 无法启动。 startScan() 仅通过回调启动一次。这可能是最好的解决方案 android-beacon-library 或使用 startScan().
  2. 自定义实现后台服务
  3. 只有警告。 Android 附近通知将于 2018 年 12 月 6 日结束 (google block)