CoreLocation - Ranging Beacons using CLBeaconIdentityConstraint does not range multiple beacons

Ranging beacons with startRangingBeacons(satisfying: CLBeaconIdentityConstraint ) does not range multiple beacons.


The newer method for ranging beacons "startRangingBeacons(satisfying: CLBeaconIdentityConstraint )", will only range the most recently added beacon, so if there are more than one beacon, we have a problem. When used the older method, "startRangingBeacons(in: region)," now deprecated but still functional in iOS 13, the app works as expected.

Details (using the newer method with "constraints"):

  1. App StartsMonitoring two Beacon regions
  2. Starts Ranging Beacons if the user enters a BeaconRegion
  3. Turn on Beacon1, the app starts ranging Beacon1
  4. Turn on Beacon2, the app starts ranging Beacon2, but does not range beacon1.

(NOTE - Both beacons regions overlap)

  • When ranged beacons with startRangingBeacons(in: region), the app was able to range both beacons.
  • But ,while ranging beacons with the latest startRangingBeacons(satisfying: CLBeaconIdentityConstraint ), didRangeBeacons only ranges the latest beacon in range and ignores the previously ranged beacons.

As soon as I start ranging for a second

CLBeaconIdentityConstraint
, I stop receiving range updates for the beacons that match the first
CLBeaconIdentityConstraint
, even though
rangedBeaconConstraints
shows both the first and second constraints.


Code sample:

import UIKit
import CoreLocation


class RangeBeaconViewController: UIViewController, CLLocationManagerDelegate {
   
   
    var locationManager = CLLocationManager()
   
    var beaconConstraints = [CLBeaconIdentityConstraint: [CLBeacon]]()
    var beacons = [CLProximity: [CLBeacon]]()
   
    override func viewDidLoad() {
        super.viewDidLoad()


        locationManager.delegate = self
        let firstUUID = UUID(uuidString: "a_valid_uuid")!
        let firstConstraint = CLBeaconIdentityConstraint(uuid: firstUUID)
        self.beaconConstraints[firstConstraint] = []
       


        let firstBeaconRegion = CLBeaconRegion(beaconIdentityConstraint: firstConstraint, identifier: firstUUID.uuidString)
        self.locationManager.startMonitoring(for: firstBeaconRegion)
       
        let secondUUID = UUID(uuidString: "another_valid_uuid")!
        let secondConstraint = CLBeaconIdentityConstraint(uuid: secondUUID)
        self.beaconConstraints[secondConstraint] = []
       
        let secondBeaconRegion = CLBeaconRegion(beaconIdentityConstraint: secondConstraint, identifier: secondUUID.uuidString)
        self.locationManager.startMonitoring(for: secondBeaconRegion)
    }
   
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)


        // Stop ranging with beacon region
//        for region in locationManager.monitoredRegions {
//            locationManager.stopRangingBeacons(in: region as! CLBeaconRegion)
//            locationManager.stopMonitoring(for: region)
//        }
       
        // Stop ranging with beaconconstraints
        for constraint in beaconConstraints.keys {
            locationManager.stopRangingBeacons(satisfying: constraint)
        }
    }


    func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
        let beaconRegion = region as? CLBeaconRegion
        //guard let beaconRegion = region as? CLBeaconRegion else{ return }
        if state == .inside {
            // Start ranging with beacon Constraint
            manager.startRangingBeacons(satisfying: beaconRegion!.beaconIdentityConstraint)
            // Start ranging with beacon region
            //manager.startRangingBeacons(in: beaconRegion)
        } else {
            // Stop ranging with beacon Constraint
            manager.stopRangingBeacons(satisfying: beaconRegion!.beaconIdentityConstraint)
            // Stop ranging with beacon region
            //manager.stopRangingBeacons(in: beaconRegion)
        }
    }


    //did range with beacon constraint
    func locationManager(_ manager: CLLocationManager, didRange beacons: [CLBeacon], satisfying beaconConstraint: CLBeaconIdentityConstraint) {
       
        beaconConstraints[beaconConstraint] = beacons
       
        for beacon in beacons {
            print("Ranging \(beacon.uuid)")
        }
    }


    //did range with beacon region
    func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
       
        beaconConstraints[region.beaconIdentityConstraint] = beacons
       
        for beacon in beacons {
            print("Ranging \(beacon.uuid)")
        }
    }
}


Is this a bug in CoreLocation, or am I missing anything.