iOS background beacon ranging Core Location


I'm building an indoor geofencing app with iBeacons. I want to detect each time a user approaches a beacon and the distance and save this data with Core Data only if the distance (proximity) to the iBeacon is close. I am using Core Location to do this but I am not using the didEnter / didExit functions as they do not provide the distance to the beacon. I am mainly using the didRange function from locationManager to get all the beacons, find the closest one and its distance.

This approach works perfectly while the app is in the foreground. However, the app starts not working properly in the background. If I just change the app, the didRange function stops working, but if I lock the phone and look at the time on the lock screen, it starts working. The problem is not that the app does not work in the background, but that the functions are activated only in specific cases or times, eg. the phone is locked.

I added these properties in the info.plist

  • Privacy - Location When In Use Usage Description
  • Privacy - Location Always and When In Use Usage Description
  • Required background modes: Location updates

I also added this code:

        locationManager.delegate = self
        locationManager.allowsBackgroundLocationUpdates = true
        locationManager.pausesLocationUpdatesAutomatically = false

This is how I add a beacon and start monitoring it:

    func addBeacon(id: String, major: Int16 = 0, minor: Int16 = 0) {
        guard let uuid = UUID(uuidString: id) else { return }
        let region = CLBeaconRegion(uuid: uuid, major: CLBeaconMajorValue(major), minor: CLBeaconMinorValue(minor), identifier: id + major.description + minor.description)
        region.notifyOnEntry = true
        region.notifyOnExit = true
        region.notifyEntryStateOnDisplay = true
        self.locationManager.startMonitoring(for: region)

    func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
        let beaconRegion = region as! CLBeaconRegion
        if state == .inside {
            // Start ranging when inside a region.
            manager.startRangingBeacons(satisfying: beaconRegion.beaconIdentityConstraint)
        } else {
            // Stop ranging when not inside a region.
            manager.stopRangingBeacons(satisfying: beaconRegion.beaconIdentityConstraint)

I am also making sure that locationManager.requestAlwaysAuthorization() is always true

Do you have any ideas why it is not always working in the background?

Thanks for your time.

Post not yet marked as solved Up vote post of Jad-T Down vote post of Jad-T


Hello Jad-T,

Did you find the solution?

Thank you.