美好的一天。在我的应用程序中,我想使用背景和前景信标扫描。对于此任务,我使用了AltBeacon库。但是在设备重启后,后台扫描无法启动。
我的算法看起来像:
启动应用程序时,启动监视器并附加生命周期侦听器 用于检测活动何时终止。
活动结束时-开始后台扫描。
当活动回到最前面时-停止背景并运行前景。
我现在所拥有的:
首先-前台“服务”(不是真正的服务,只是课程)
class BeaconForegroundService(private val application: Application) : BeaconConsumer {
private var beaconManager: BeaconManager? = null
companion object {
private const val REGION_UID = "region_uid"
}
override fun getApplicationContext(): Context {
return application.applicationContext
}
override fun unbindService(p0: ServiceConnection) {
application.unbindService(p0)
}
override fun bindService(p0: Intent, p1: ServiceConnection, p2: Int): Boolean {
return application.bindService(p0, p1, p2)
}
override fun onBeaconServiceConnect() {
beaconManager!!.beaconParsers.clear()
beaconManager!!.beaconParsers.add(AltBeaconParser())
beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.URI_BEACON_LAYOUT))
beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_TLM_LAYOUT))
beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT))
beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_URL_LAYOUT))
beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"))
beaconManager!!.backgroundMode = false
beaconManager!!.addMonitorNotifier(object : MonitorNotifier {
override fun didDetermineStateForRegion(p0: Int, p1: Region?) {
Timber.d("FGBeacon: didDetermineStateForRegion INSIDE = ${p0 == MonitorNotifier.INSIDE}")
}
override fun didEnterRegion(p0: Region?) {
Timber.d("FGBeacon: didEnterRegion")
}
override fun didExitRegion(p0: Region?) {
Timber.d("FGBeacon: didExitRegion")
}
})
beaconManager!!.addRangeNotifier { mutableCollection: MutableCollection<Beacon>, region: Region ->
Timber.d("FGBeacon $mutableCollection")
}
beaconManager!!.startMonitoringBeaconsInRegion(Region(REGION_UID, null, null, null))
beaconManager!!.startRangingBeaconsInRegion(Region(REGION_UID, null, null, null))
}
fun startScan() {
beaconManager = BeaconManager.getInstanceForApplication(application)
beaconManager!!.bind(this)
}
fun stopScan() {
beaconManager?.unbind(this)
}
}
应用程序类内部的背景扫描:
class MyApplication : Application(), BootstrapNotifier {
// Fields
private var beaconManager: BeaconManager? = null
private var backgroundPowerSaver: BackgroundPowerSaver ?= null
private var regionBootstrap : RegionBootstrap ?= null
private var foregroundService: BeaconForegroundService ?= null
val REGION_UID = "region_uid"
//Method for start background scan here
fun startScan() {
beaconManager = BeaconManager.getInstanceForApplication(this)
beaconManager!!.beaconParsers.clear()
beaconManager!!.beaconParsers.add(AltBeaconParser())
beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.URI_BEACON_LAYOUT))
beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_TLM_LAYOUT))
beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT))
beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_URL_LAYOUT))
beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"))
val notificationBuilder = Notification.Builder(this)
notificationBuilder.setSmallIcon(R.drawable.ic_launcher_foreground)
notificationBuilder.setContentTitle("Scanning for beacons")
val intent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, MainActivity.BEACON_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
notificationBuilder.setContentIntent(pendingIntent)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("MyChannelId", "NotyName", NotificationManager.IMPORTANCE_DEFAULT)
channel.description = "NotyDesc"
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
notificationBuilder.setChannelId(channel.id)
}
val region = Region(REGION_UID, null, null, null)
beaconManager!!.enableForegroundServiceScanning(notificationBuilder.build(), 456)
beaconManager!!.setEnableScheduledScanJobs(false)
beaconManager!!.backgroundBetweenScanPeriod = 0
beaconManager!!.backgroundScanPeriod = TimeUnit.SECONDS.toMillis(5)
beaconManager!!.backgroundMode = true
regionBootstrap = RegionBootstrap(this, region)
backgroundPowerSaver = BackgroundPowerSaver(this)
beaconManager!!.addRangeNotifier { mutableCollection: MutableCollection<Beacon>, r: Region ->
Timber.d("PBeacon $mutableCollection")
}
}
//Disable background scan if application start in foreground
fun disableMonitoring() {
regionBootstrap?.disable()
regionBootstrap = null
beaconManager?.removeAllRangeNotifiers()
}
override fun didDetermineStateForRegion(p0: Int, p1: Region?) {
Timber.d("PBeacon: StateForRegion INSIDE = ${p0 == MonitorNotifier.INSIDE}")
}
//Start ranging if we inside region
override fun didEnterRegion(p0: Region?) {
Timber.d("PBeacon: I see a beacon first time")
beaconManager!!.startRangingBeaconsInRegion(Region(REGION_UID, null, null, null))
}
//Stop ranging if we move out from region
override fun didExitRegion(p0: Region?) {
Timber.d("PBeacon : I no longer see a beacon.")
beaconManager!!.stopRangingBeaconsInRegion(Region(REGION_UID, null, null, null))
}
最后-注册的侦听器,用于检测前景/后台应用程序状态变化(在应用程序的onCreate内部)
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
//Stop background scan and start foreground
override fun onActivityStarted(activity: Activity?) {
disableMonitoring()
foregroundService = BeaconForegroundService(this@MyApplication)
foregroundService!!.startScan()
}
//Stop foreground scan and start background
override fun onActivityStopped(activity: Activity?) {
foregroundService?.stopScan()
foregroundService = null
startScan()
}
})
在此处登录:
在前台启动应用程序时记录日志(看起来不错)
D/BeaconParser: Parsing beacon layout: m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
D/BeaconParser: Parsing beacon layout: m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
D/BeaconParser: Parsing beacon layout: s:0-1=fed8,m:2-2=00,p:3-3:-41,i:4-21v
D/BeaconParser: Parsing beacon layout: x,s:0-1=feaa,m:2-2=20,d:3-3,d:4-5,d:6-7,d:8-11,d:12-15
D/BeaconParser: Parsing beacon layout: s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19
D/BeaconParser: Parsing beacon layout: s:0-1=feaa,m:2-2=10,p:3-3:-41,i:4-21v
D/BeaconParser: Parsing beacon layout: m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
....
BeaconForegroundService$onBeaconServiceConnect: [id1: b5b182c7-eab1-4988-aa99-b5c1517008d9 id2: 1 id3: 57197]
关闭应用程序(后台模式?):
Processing pdu type FF: 0201061aff4c000215b5b182c7eab14988aa99b5c1517008d90001df6dc50d0961626561636f6e5f36444446000000000000000000000000000000000000 with startIndex: 5, endIndex: 29
D/BeaconParser: This is not a matching Beacon advertisement. Was expecting aa fe at offset 5 and 20 at offset 7. The bytes I see are: 0201061aff4c000215b5b182c7eab14988aa99b5c1517008d90001df6dc50d0961626561636f6e5f36444446000000000000000000000000000000000000
D/BeaconParser: Ignoring pdu type 01
...
D/BeaconParser: Processing pdu type FF: 0201061aff4c000215b5b182c7eab14988aa99b5c1517008d90001df6dc50d0961626561636f6e5f36444446000000000000000000000000000000000000 with startIndex: 5, endIndex: 29
D/BeaconParser: This is a recognized beacon advertisement -- 02 15 seen
D/BeaconParser: Bytes are: 0201061aff4c000215b5b182c7eab14988aa99b5c1517008d90001df6dc50d0961626561636f6e5f36444446000000000000000000000000000000000000
D/ScanHelper: Beacon packet detected for: id1: b5b182c7-eab1-4988-aa99-b5c1517008d9 id2: 1 id3: 57197 with rssi -46
D/RangeState: adding id1: b5b182c7-eab1-4988-aa99-b5c1517008d9 id2: 1 id3: 57197 to existing range for: org.altbeacon.beacon.service.RangedBeacon@332c859
重启后:
I/BeaconManager: BeaconManager started up on pid 7407 named 'com.myapp' for application package 'com.myapp'. isMainProcess=true
D/BeaconParser: Parsing beacon layout: m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
仅此而已。没有检测到,等待中(超过20分钟)
所以
非常感谢