Android iBeacon Detection Fails intermittenly

84 Views Asked by At

I'm using Altbeacon library 2.17.1 (Xamarin forms) to detect ibeacons when the app is in the foreground. The issue that I'm facing is the DidRangeBeaconsInRegion method is called with an empty list of beacons intermittently. Most of the time the beacon is detected, however, it returns an empty list every 4 - 5 seconds for a few cycles. I have also noticed that if I increase the ForegroundScanPeriod and the ForegroundBetweenScanPeriod, the frequency of getting an empty list reduces, but still occurs. On iOS, using the CLLocationManager, the same beacon is detected and I never get a failure.

Here is the code that I have for beacon detection.

\`
public class BluetoothBeaconService: Java.Lang.Object, IBeaconConsumer, IRangeNotifier
{
   public Context ApplicationContext = context;
   private Context context;

    public class BluetoothBeaconService : Java.Lang.Object, IBeaconConsumer, IRangeNotifier
    {   
        private BeaconManager beaconMgr;
        private Region rangingRegion;
    
        private bool _didRanageBeaconsCalled = false;
        private bool _beaconServiceConnected = false;
    
        public BluetoothBeaconService(Context context)
        {
            this.context = context;
            beaconMgr = BeaconManager.GetInstanceForApplication(context);
    
            var iBeaconParser = new BeaconParser();
       
            iBeaconParser.SetBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24");
            beaconMgr.BeaconParsers.Add(iBeaconParser);
            rangingRegion = new    
            Region("id",Identifier.Parse(AppEnvVariables.BluetootheBeaconUUID),null, null);
            beaconMgr.BackgroundMode = false;
            beaconMgr.Bind(this);
        }
    
        public void OnBeaconServiceConnect()
        {
            if (!App.Instance.UISettings.ShowAccessTab)
                return;
    
            beaconMgr.ForegroundScanPeriod = 1000;
            beaconMgr.ForegroundBetweenScanPeriod = 0; 
            beaconMgr.UpdateScanPeriods();
            beaconMgr.AddRangeNotifier(this);
            beaconMgr.StartRangingBeaconsInRegion(rangingRegion);
    
            _beaconServiceConnected = true;
        }
    
        public void PauseBeaconService()
        {
            if (_beaconServiceConnected)
            {
                beaconMgr.StopRangingBeaconsInRegion(rangingRegion);
                beaconMgr.Unbind(this);
            }
        }
    
        public void ResumeBeaconService()
        {
            if (_beaconServiceConnected)
            {
                beaconMgr.Bind(this);
                beaconMgr.StartRangingBeaconsInRegion(rangingRegion);
            }
        }
    
        public void DidRangeBeaconsInRegion(ICollection<AltBeaconOrg.BoundBeacon.Beacon> beacons, 
        Region region)
        {
            Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
            {
                if (_didRanageBeaconsCalled
                || beacons == null || !beacons.Any()
                || !App.Instance.IsLoggedIn
                || App.Instance.AccessStatusListener == null) 
                    return;
    
                _didRanageBeaconsCalled = true;
                try
                {
                    var models = new List<UbiParkApp.Core.Models.Beacon>();
                    foreach (var beacon in beacons)
                    {
                        models.Add(beacon.ToModel());
                    }
    
                    if (!App.Instance.IsInBackground)
                    {
                        _ = App.Instance.AccessStatusListener.HandleRangedBeacons(models);
                    }
                }
                catch (Exception ex)
                {
                    var logger = App.Container.Resolve<ILogger>();
                    logger?.TrackError(ex, nameof(BluetoothBeaconService), 
                    nameof(DidRangeBeaconsInRegion), DeviceHelper.UUID);
                }
                finally
                {
                    _didRanageBeaconsCalled = false;
                }
            });
        }
    
    
        public bool BindService(Intent intent, IServiceConnection connection, Bind bind)
        {
            return context.BindService(intent, connection, bind);
        }
    
        public void UnbindService(IServiceConnection connection)
        {
            context.UnbindService(connection);
        }    
    }`

I also used the Beacon Scope app to detect the beacon and it shows a 68% detection rate.

The app is currently using Xamarin Forms (4.8) and currently unable to update to the latest, due to some dependant nuget packages. Could this be the reason for the intermittent empty beacon list.

The second question is there another nuget version that is available (other than 2.7 which supports .NetFranework) that could be compiled with Android 12 or higher. The current 2.17.1 has the issue of Andoird.Exported not being defined.

I have tried using older versions and the results are the same. Testing with multiple beacons, the beacon list will most of the time return a valid list, however the number of beacons detected varied intermittently.

1

There are 1 best solutions below

4
davidgyoung On

The fact that BeaconScope shows a 68 percent detection rate points to the problem. A properly advertising beacon transmitter should yield a detection rate of about 90 percent or more.

Lower detection rates typically indicate that the transmitter is not advertising frequently enough. The spec for Apple’s iBeacon requires manufacturers to make their hardware transmit at 10 Hz for correct results. Some manufacturers, however, use a lower transmission rate of 1Hz or even 0.5 Hz to make battery life last longer. (BaconScope will give you an estimate of this advertising rate, too.)

While it is not as obvious with iOS APIs, iOS experiences the same periodic dropouts with low transmission rate beacons. When a ranging cycle has no detections, CoreLocation CLBeacon object will have a rssi of 0 and an accuracy of -1. Only after 5-10 cycles n a row with no detections will it drop off the list of detected beacons.

The Android Beacon Library does not work this way — it simply drops a beacon off the list for any cycle where it is not detected. (I am the original author of the library and wrote it this way because I believe it is a more obvious and expected behavior and does not obscure what is going on as is the case with CoreLocation.) Long story short, the Android behavior you see is as designed.

If you want the iOS like behavior, you can add code to your app to continue tracking beacons on Android despite brief dropouts. Simply add a map structure of detected beacons along with a counter of how many cycles there have been since the last detection, and drop the beacon from the map only after 5 cycles without detection.

I am the lead developer on the native library project but I am not a Xamarin expert, so I cannot speak to the package problem with the 2.7.1 Nuget version. You may want to report that problem to that package maintainer.

However, I can confirm there are no changes to this behavior in newer versions of the library, so getting a newer version will not change this.