Добрый день.В моем приложении я хочу использовать фоновое и переднее сканирование маяков.Для этой задачи я использовал библиотеку 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+ минут)
Итак
- Это ошибка библиотеки / устройства или я что-то не так делаю?
- Можно ли использовать фоновое сканирование безУведомление?
- Когда мы запускаем приложение снова (на передний план), уведомление обновляется.Как я могу избежать этого?
Большое спасибо