在 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+ 上的信标扫描。但要使其工作,您必须使用 BeaconManager
或 RegionBootsrap
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 class 和 Service class here.
- 2 次通知调用
- 延迟处理程序
结果:
我的服务是在 MainActivity 上启动的,它启动了我的 ScannerService。我在 MainActivity(当用户打开应用程序时)的前台 onStartCommand 中将其设置为 运行 并保持 运行ning 直到他们锁定屏幕。屏幕锁定后,应用程序将进入基于屏幕 activity 的循环。
当用户解锁 phone(在 Android 7- 上)时,前台通知会立即清除,因为服务会切换到后台服务。在 Android 8 上,向用于启动前台 BeaconManager 服务的相同 ID 发送通知,然后在切换到后台设置的 2.5 秒后取消处理程序上的通知。该通知会阻止用户收到 "Background Services are Using Battery" 通知,但它足够短,可以在他们解锁屏幕之前消失。
我的测试结果:
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来解决
- Api <= 26
startScan() 不支持 PendingIntent - BroadcastReceiver 无法启动。 startScan() 仅通过回调启动一次。这可能是最好的解决方案 android-beacon-library 或使用 startScan().
自定义实现后台服务
- 只有警告。 Android 附近通知将于 2018 年 12 月 6 日结束 (google block)
我的应用使用 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+ 上的信标扫描。但要使其工作,您必须使用 BeaconManager
或 RegionBootsrap
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 class 和 Service class here.
- 2 次通知调用
- 延迟处理程序
结果:
我的服务是在 MainActivity 上启动的,它启动了我的 ScannerService。我在 MainActivity(当用户打开应用程序时)的前台 onStartCommand 中将其设置为 运行 并保持 运行ning 直到他们锁定屏幕。屏幕锁定后,应用程序将进入基于屏幕 activity 的循环。
当用户解锁 phone(在 Android 7- 上)时,前台通知会立即清除,因为服务会切换到后台服务。在 Android 8 上,向用于启动前台 BeaconManager 服务的相同 ID 发送通知,然后在切换到后台设置的 2.5 秒后取消处理程序上的通知。该通知会阻止用户收到 "Background Services are Using Battery" 通知,但它足够短,可以在他们解锁屏幕之前消失。
我的测试结果:
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来解决
- Api <= 26 startScan() 不支持 PendingIntent - BroadcastReceiver 无法启动。 startScan() 仅通过回调启动一次。这可能是最好的解决方案 android-beacon-library 或使用 startScan(). 自定义实现后台服务
- 只有警告。 Android 附近通知将于 2018 年 12 月 6 日结束 (google block)