Android 当应用程序处于后台时,altbeacon 的间隔

Android altbeacon ranging in intervals when app in background

我正在开发一个运行后台服务的应用程序,以间隔地测量蓝牙信标。

我启动一个带有定时器的ForegroundService,每分钟开始测距10秒,间隔200毫秒,计算出最强的信标并提交给后端API。

当应用程序处于前台时,这可以很好地工作,并且当屏幕关闭时,只要我使用 adb logcat 连接。一旦我把它取下来,就再也没有任何东西被提交到服务器,这意味着不再有信标被测距。

下面是相关的代码片段,希望我没有简化太多:

class BeaconService : Service(), BeaconConsumer {
    private var beaconManager: BeaconManager? = null
    private var rangingTimer = Timer("rangingTimer", true)
    private val region = Region("com.beacon.test", Identifier.parse("f7826da6-4fa2-4e98-8024-bc5b71e0893e"), null, null)

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        return Service.START_STICKY
    }

    override fun onCreate() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationManager = MyNotificationManager.getInstance()
            val notification = notificationManager.buildBeaconServiceNotification(this, "iBeacon service", null)
            startForeground(NOTIFICATION_ID, notification)
        }

        initBeaconManager()
    }

    private fun initBeaconManager() {
        BeaconManager.setDebug(true)
        beaconManager = BeaconManager.getInstanceForApplication(this)
        beaconManager?.foregroundScanPeriod = 200L
        beaconManager?.beaconParsers?.add(BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"))
        beaconManager?.bind(this)
    }

    override fun onBeaconServiceConnect() {
        beaconManager?.addRangeNotifier { beacons, _ ->
            if (beacons.isNotEmpty()) {
                //code add ranged beacons to list
            }
        }
        startRanging()
    }

    private fun startRanging() {

        //code to reset the list of ranged beacons

        beaconManager?.startRangingBeaconsInRegion(region)

        rangingTimer.schedule(10000L) {
            stopRanging(50000L)
        }

    }

    private fun stopRanging(restartRangingAfter: Long? = null) {
        beaconManager?.stopRangingBeaconsInRegion(region)

        //code calcuate the strongest beacon and submit to server

        if (restartRangingAfter != null) {
            rangingTimer.schedule(restartRangingAfter) {
                startRanging()
            }
        }
    }
}

在 OS 版本 8+ 上,Android 限制后台处理,除非它是前台服务的一部分或由 JobScheduler 启动的作业。由于此限制,Android Beacon 库将默认使用 Android 8+ 上的 JobScheduler。在前台,一个 "immediate" ScanJob 将 运行 不断地进行扫描。在后台(意味着当屏幕解锁时没有活动可见时),Android 不允许这样做。最多每 15 分钟安排一次作业。这就是您看到扫描停止的原因。

有自己的前台服务也没关系。 Android 仍然对在该前台服务之外执行的任何后台处理执行这些限制。

两种选择:

  1. 接受作业限制(每 15 分钟扫描一次)。使用 BackgroundPowerSaver 在 foreground/background 模式之间自动切换并设置 beaconManager.setBackgroundScanPeriod(5000)(每 15 分钟扫描 5 秒。)为了清楚起见,您还应该设置 beaconManager.setBackgroundBetweenScanPeriod(15*60*1000)(15 分钟),尽管您可以设置一个较低的值,该值将被 Android 8+ 上的 OS 禁止。

  2. 如果您想保留两个前台服务并只显示一个通知,请按照here. You can then stop using your own foreground service, or keep it. If you keep it, you will see two notification icons about the two foreground services running. It is possible to combine those two notifications所述将库设置为使用自己的前台服务进行扫描(是的,作为第二个前台服务)。