Altbeacon не находит маяки на Android 8+

Я использую маяк Alt в своем проекте для обнаружения маяков, он отлично работает на моем Samsung s7 (Android 7), но на Samsung s10, Oneplus 6 и Google Pixel 3 XL (Android 9/10) он не работает на все.

Код просто не находит никаких маяков.

Мой код начинается с проверки разрешений:

if (ContextCompat.checkSelfPermission(view, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    Log.d(TAG, "Requesting Permission.")
    openPermissionDialog()
} else {
    startBeacon()
}

Затем внутри моего начального кода маяка включается bluetooth, и я создаю свой диспетчер маяков.

val mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
    if(mBluetoothAdapter != null){
         if (!mBluetoothAdapter.isEnabled) {
                mBluetoothAdapter.enable()
         }

         Log.d(TAG, "Permissions accepted, bluetooth is on.")

         model.beaconManager = BeaconManager.getInstanceForApplication(view)
         BeaconController.startBeacon(model.beaconManager, view)
    }

Наконец, внутри BeaconController у меня есть одноэлементный объект-компаньон, который будет связывать маяк каждые 20 минут. Это потому, что когда я нахожу маяк, он отвязывается.

class BeaconController {

    companion object {

        private val TAG = "HomePresenter"
        private var hasTimerStarted = false

        fun startBeacon(beaconManager: BeaconManager?, view: HomeActivityView) {

            if (!hasTimerStarted) {

                Log.d(TAG, "Timer starting")
                hasTimerStarted = true

                val handler = Handler()
                Thread(object : Runnable {
                    override fun run() {

                        if (beaconManager?.isBound(view) != null) {
                            Log.d(TAG, "Beacon binding")
                            beaconManager.bind(view)
                            beaconManager.beaconParsers.clear()
                            beaconManager.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT))
                        } else {
                            Log.d(TAG, "Beacon is bound")
                        }

                        handler.postDelayed(this, 1200000) // 20 Minutes

                    }
                }).start()

            } else {
                Log.d(TAG, "Timer already started.")
            }

        }

    }

}

Как только маяк привязан, я запускаю некоторую логику в своем onBeaconServiceConnect для отправки аналитики, когда я нахожу маяк.

  override fun onBeaconServiceConnect() {
        model.beaconManager?.addRangeNotifier { beacons, _ ->
            if (beacons.isNotEmpty()) {
                val firstBeacon = beacons.iterator().next()
                val firstBeaconNameSpace = "${firstBeacon.id1}".replace("0x", "")
                val firstBeaconIdentifier = "${firstBeacon.id2}".replace("0x", "")

                Log.d(TAG, "Beacon $firstBeaconNameSpace - $firstBeaconIdentifier is " + firstBeacon.distance + " meters away.")

            }
        }

        /**
         * Attach
         */

        try {
            model.beaconManager?.startRangingBeaconsInRegion(Region("com.MYAPP.MYAPP", null, null, null))
            Log.d(TAG, "Added Range Notifier")
        } catch (e: RemoteException) {
            Log.d(TAG, "Error adding Range Notifier")
            e.printStackTrace()
        }


    }

person JoshB99    schedule 21.01.2020    source источник


Ответы (3)


Проблема, вероятно, не имеет ничего общего с библиотекой Android Beacon, а просто связана с ограничениями операционной системы Android на использование таймеров на Android 8+.

Начиная с версии 8, приложения Android завершаются операционной системой через 10 минут фонового выполнения, если ForegroundService не активен. Поэтому этот таймер НИКОГДА не сработает, если вы не оставите экран включенным, разблокированным и приложение не будет видно на экране: handler.postDelayed(this, 1200000) // 20 Minutes

Вы можете изменить свою архитектуру, чтобы это работало на Android 8+, или вы можете настроить библиотеку для использования встроенного ForegroundService, чтобы обойти ограничение. Инструкции см. здесь.

person davidgyoung    schedule 21.01.2020
comment
Спасибо за ответ. Вариант использования моего приложения находится только на переднем плане, мне не нужно слушать в фоновом режиме. Даже если я оставлю приложение открытым на экране, где привязывается маяк, оно никогда не найдет маяк. Где устройство Android 7 находит его примерно через 20 секунд (как и ожидалось) - person JoshB99; 21.01.2020
comment
Вы в этом уверены? Потребуется немало усилий, чтобы оставить экран включенным в течение 20 минут подряд, не давая ему выключить экран или заблокировать телефон. Вы также упоминаете 20 секунд в комментарии выше, но в коде четко указано 20 минут. - person davidgyoung; 21.01.2020
comment
Да, это внутри обработчика, это означает, что код будет запущен один раз мгновенно, а затем снова в течение 20 минут. Затем он будет привязан к потребителю. Затем телефон найдет маяки (примерно в течение 20 секунд). Как только он найдет маяк, потребитель отвяжется. - person JoshB99; 21.01.2020
comment
Код внутри потока будет запущен, затем обработчик задержится на 1200000 миллисекунд и снова запустит этот код. - person JoshB99; 21.01.2020

Я знаю, потому что у меня были проблемы, когда я работал с маяками, что для устройств с Oreo и выше фоновая задача не работает.

Для этих устройств я использовал JobScheduler....

Это руководство по этому поводу https://www.youtube.com/watch?v=3EQWmME-hNA

Я надеюсь, что смогу помочь вам ;)

Удачи

person Carlos Cabello Ruiz    schedule 21.01.2020

Причина, по которой это не сработало, заключается в том, что я привязывал маяк до фактического добавления макета маяка...

До:

beaconManager?.bind(view)
beaconManager?.beaconParsers?.clear()
beaconManager?.beaconParsers?.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT))

После:

beaconManager?.beaconParsers?.clear()
beaconManager?.beaconParsers?.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT))
beaconManager?.bind(view)
person JoshB99    schedule 21.01.2020
comment
Рад слышать, что вы нашли решение. - person davidgyoung; 22.01.2020