androidkotlinaltbeaconeddystone

Altbeacon not finding beacons on android 8+


I'm using Alt beacon in my project to detect beacons, it is working perfectly on my Samsung s7 (Android 7) but on a Samsung s10, Oneplus 6 and Google Pixel 3 XL (Android 9/10) it doesn't work at all.

The code just doesn't seem to find any beacons.

My code starts with a permission check:

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

Then inside of my start beacon code bluetooth gets turned on and I create my beacon manager

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)
    }

Lastly inside of BeaconController I have a singleton companion object that will bind the beacon every 20 minutes. This is because when I find a beacon it will unbind.

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.")
            }

        }

    }

}

Once the beacon is bound I run some logic in my onBeaconServiceConnect to send an analytic when I find a beacon

  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()
        }


    }

Solution

  • The reason this wasn't working is because I was binding the beacon before actually adding the Beacon layout...

    Before:

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

    After:

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