-2 C
New York
Friday, February 21, 2025

bluetooth lowenergy – Learn how to Constantly Detect iBeacons in Background and Sleep Mode on iOS utilizing .NET MAUI


I’m creating a .NET MAUI utility that makes use of iBeacon to unlock a door when the person approaches a beacon. In accordance with the documentation, StartRangingBeacons works solely when the app is energetic, whereas StartMonitoring ought to nonetheless perform even when the app is within the background or the iPhone is locked. Nevertheless, I’m going through a problem: RegionEntered and RegionLeft occasions are usually not being triggered as anticipated when the app is within the background or when the cellphone is locked.

  1. Why are RegionEntered and RegionLeft occasions not triggered whereas utilizing iBeacon monitoring within the background on iOS?
  2. How can I be certain that iBeacon detection works reliably when the app is within the background or the cellphone is locked?
  3. Is it attainable to set off BLE scanning utilizing Plugin.BLE upon beacon detection within the background?

My present method:

  1. I exploit CoreLocation for iBeacon monitoring and detection.
  2. When the RegionEntered occasion is triggered, I wish to begin scanning with Plugin.BLE to ascertain a reference to the detected beacon.
  3. BLE communication works superb when the app is energetic, however I’m struggling to make sure dependable operation within the background.

Thanks

Service class:

utilizing CoreLocation;
utilizing Basis;

namespace EntercamPass.Platforms.iOS.Companies;

public class BeaconManager : CLLocationManagerDelegate
{
    protected static BeaconManager _instance;
    protected static readonly object _lock = new object();

    protected readonly CLLocationManager _locationManager;
    protected CLBeaconRegion _beaconRegion;

    protected static bool _isScanning;

    protected const string BLE_SERVICE_UID = "0000fff0-454e-5445-5243-414d2d424c45";
    protected const string BEACON_REGION = "com.entercam.go.beacon";

    public BeaconManager()
    {
        _locationManager = new CLLocationManager
        {
            Delegate = this,
            AllowsBackgroundLocationUpdates = true,
            PausesLocationUpdatesAutomatically = false
        };
        _locationManager.RequestAlwaysAuthorization();

        _beaconRegion = new CLBeaconRegion(new NSUuid(BLE_SERVICE_UID), BEACON_REGION)
        {
            NotifyEntryStateOnDisplay = true,
            NotifyOnEntry = true,
            NotifyOnExit = true
        };
    }

    public static BeaconManager Occasion
    {
        get
        {
            lock (_lock)
            {
                return _instance ??= new BeaconManager();
            }
        }
    }

    public void CheckAndUpdateServiceState()
    {
        if (CLLocationManager.Standing == CLAuthorizationStatus.AuthorizedAlways)
        {
            StartScanning();
        }
        else
        {
            Console.WriteLine("Не хватает разрешений на использование местоположения.");
            StopScanning();
        }
    }

    non-public void StartScanning()
    {
        if (_isScanning) return;

        _isScanning = true;
        _locationManager.StartMonitoring(_beaconRegion);
        _locationManager.StartRangingBeacons(_beaconRegion);

        Console.WriteLine("Began scanning for beacons.");
    }

    non-public void StopScanning()
    {
        if (_isScanning == false) return;

        _isScanning = false;
        _locationManager.StopMonitoring(_beaconRegion);
        _locationManager.StopRangingBeacons(_beaconRegion);

        Console.WriteLine("Stopped scanning for beacons.");
    }
    
    public void OnAppDidEnterBackground()
    {
        Console.WriteLine("App entered background. Monitoring continues.");
        
        CheckAndUpdateServiceState();
    }

    public void OnAppWillEnterForeground()
    {
        Console.WriteLine("App will enter foreground. Resuming ranging.");
        
        CheckAndUpdateServiceState();
    }

    public override void DidDetermineState(CLLocationManager supervisor, CLRegionState state, CLRegion area)
    {
        Console.WriteLine($"Определено состояние: {state} для региона {area.Identifier}");

        if (state == CLRegionState.Inside && area is CLBeaconRegion beaconRegion1)
        {
            _locationManager.StartRangingBeacons(beaconRegion1);
            Console.WriteLine("Began ranging beacons inside area.");
        }
        else if (state == CLRegionState.Exterior && area is CLBeaconRegion beaconRegion2)
        {
            _locationManager.StopRangingBeacons(beaconRegion2);
            Console.WriteLine("Stopped ranging beacons exterior area.");
        }
    }

    public override void RegionEntered(CLLocationManager supervisor, CLRegion area)
    {
        Console.WriteLine($"Entered area: {area.Identifier}");
        if (area is CLBeaconRegion beaconRegion)
        {
            //_locationManager.StartRangingBeacons(beaconRegion);
            Console.WriteLine("Began ranging beacons.");
        }
    }

    public override void RegionLeft(CLLocationManager supervisor, CLRegion area)
    {
        Console.WriteLine($"Left area: {area.Identifier}");
        if (area is CLBeaconRegion beaconRegion)
        {
            _locationManager.StopRangingBeacons(beaconRegion);
            
            Console.WriteLine("Stopped ranging beacons.");
        }
    }
    
    public override void DidRangeBeacons(CLLocationManager supervisor, CLBeacon[] beacons, CLBeaconRegion area)
    {
        if (beacons.Size > 0)
        {
            foreach (var beacon in beacons)
            {
                Console.WriteLine($"Beacon detected: UUID={beacon.ProximityUuid}, Main={beacon.Main}, Minor={beacon.Minor}, RSSI={beacon.Rssi}");
            }
        }
        else
        {
            Console.WriteLine("No beacons detected.");
        }
    }

    public override void Failed(CLLocationManager supervisor, NSError error)
    {
        base.Failed(supervisor, error);

        Console.WriteLine($"Location Supervisor error: {error.LocalizedDescription}");
    }

    public override void LocationUpdatesPaused(CLLocationManager supervisor)
    {
        base.LocationUpdatesPaused(supervisor);
        
        Console.WriteLine($"LocationUpdatesPaused:");
    }

    public override void DidFailRangingBeacons(CLLocationManager supervisor, CLBeaconIdentityConstraint beaconConstraint, NSError error)
    {
        base.DidFailRangingBeacons(supervisor, beaconConstraint, error);
        
        Console.WriteLine($"DidFailRangingBeacons");
    }

    public override void MonitoringFailed(CLLocationManager supervisor, CLRegion? area, NSError error)
    {
        base.MonitoringFailed(supervisor, area, error);
        
        Console.WriteLine($"MonitoringFailed: {error.ToString()}");
    }
}

Information.plist:




    
        LSRequiresIPhoneOS
        
        UIDeviceFamily
        
            1
            2
        
        UIRequiredDeviceCapabilities
        
            bluetooth-le
        
        UISupportedInterfaceOrientations
        
            UIInterfaceOrientationPortrait
            UIInterfaceOrientationLandscapeLeft
            UIInterfaceOrientationLandscapeRight
        
        UISupportedInterfaceOrientations~ipad
        
            UIInterfaceOrientationPortrait
            UIInterfaceOrientationPortraitUpsideDown
            UIInterfaceOrientationLandscapeLeft
            UIInterfaceOrientationLandscapeRight
        
        XSAppIconAssets
        Belongings.xcassets/appicon.appiconset
        CFBundleIdentifier
        com.entercam.go
        
        UIBackgroundModes
        
            processing
            fetch
            location
            bluetooth-central
            bluetooth-peripheral
        
        
        NSLocationWhenInUseUsageDescription
        Это приложение требует доступ к вашему местоположению для работы с BLE устройствами.
        NSLocationAlwaysUsageDescription
        Это приложение требует постоянного доступа к вашему местоположению для работы с BLE устройствами.
        NSLocationAlwaysAndWhenInUseUsageDescription
        Это приложение требует доступ к вашему местоположению как в активном, так и в фоновом режиме для работы с BLE устройствами.
        NSBluetoothAlwaysUsageDescription
        Это приложение требует доступ к Bluetooth для обнаружения устройств.
        NSBluetoothPeripheralUsageDescription
        Мы используем Bluetooth для связи с устройствами.
        NSUserNotificationUsageDescription
        Это приложение требует доступ для отправки уведомлений.
    

MauiProgram:

utilizing CommunityToolkit.Maui;
utilizing EntercamPass.Instruments;
utilizing Microsoft.Extensions.Logging;
utilizing Shiny;

namespace EntercamPass;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder()
            .UseMauiApp()
            .UseMauiCommunityToolkit()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Common.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                fonts.AddFont("MaterialIcons-Common.ttf", "MaterialIconsRegular");
            });

#if DEBUG
        builder.Logging.AddDebug();
#endif

#if ANDROID
        builder.Companies.AddSingleton();
#endif

#if IOS
        builder.Companies.AddSingleton(Platforms.iOS.Companies.BeaconManager.Occasion);
#endif
        GlobalExceptionHandler.Init();

        MauiApp mauiApp = builder.Construct();

        return mauiApp;
    }
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles