问题
So, we have encountered a problem, developing in Swift for iOS 13. When we use the newer method for ranging beacons "startRangingBeacons(satisfying: CLBeaconIdentityConstraint )" it will only range the most recently added beacon, so if there are more than one beacon, we have a problem. When we use 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"):
- App StartsMonitoring 2 Beacon regions
- Starts Ranging Beacons if the user enters a BeaconRegion
- Turn on Beacon1, the app starts ranging Beacon1
- Turn on Beacon2, the app starts ranging Beacon2, but does not range beacon1. (NOTE - Both beacons regions overlap, and the older method can handle this)
When ranged beacons with startRangingBeacons(in: region), the app was able to range both beacons.
When the latest ranged beacon is turned off, didRangeBeacons event is triggered with empty CLBeacon list, which should still have the other beacon in, but it does not.
Here is the code that does not work:
func locationManager(_ manager: CLLocationManager, didRange beacons: [CLBeacon], satisfying beaconConstraint: CLBeaconIdentityConstraint) {
for beacon in beacons {
if [.near, .immediate].contains(beacon.proximity){
if let index = beaconsInProximity.firstIndex(of: beacon) {
beaconsInProximity.remove(at: index)
}
beaconsInProximity.append(beacon)
if beaconsInProximity.count > 1 { beaconsInProximity = beaconsInProximity.sorted(by: {$0.accuracy < $1.accuracy})}
if nearestBeacon == nil || !nearestBeacon!.isEqual(beaconsInProximity[0]) {
if(nearestBeacon != nil) {
notifyUser(isExiting: true, isBeacon = true)
}
nearestBeacon = beaconsInProximity[0]
displayOrSendNotification()
}
} else if let index = beaconsInProximity.firstIndex(of: beacon){
if(beaconsInProximity.count > 1) {
beaconsInProximity.remove(at: index)
if nearestBeacon != nil && nearestBeacon!.isEqual(beacon) {
notifyUser(isExiting: true, isBeacon = true)
nearestBeacon = beaconsInProximity.count > 0 ? beaconsInProximity[0] : nil
displayOrSendNotification()
}
}
}
}
}
Here is the code that works:
func locationManager(_ manager: CLLocationManager,
didRangeBeacons beacons: [CLBeacon],
in region: CLBeaconRegion) {
print("Did range beacons")
for beacon in beacons {
if [.near, .immediate].contains(beacon.proximity){
if let index = beaconsInProximity.firstIndex(of: beacon) {
beaconsInProximity.remove(at: index)
}
beaconsInProximity.append(beacon)
if beaconsInProximity.count > 1 { beaconsInProximity = beaconsInProximity.sorted(by: {$0.accuracy < $1.accuracy})}
if nearestBeacon == nil || !nearestBeacon!.isEqual(beaconsInProximity[0]) {
if(nearestBeacon != nil) {
displayOrSendNotification(isExiting: true, isBeacon: true)
}
nearestBeacon = beaconsInProximity[0]
displayOrSendNotification(isExiting: false, isBeacon: true)
}
} else if let index = beaconsInProximity.firstIndex(of: beacon){
if(beaconsInProximity.count > 1) {
beaconsInProximity.remove(at: index)
if nearestBeacon != nil && nearestBeacon!.isEqual(beacon) {
nearestBeacon = beaconsInProximity.count > 0 ? beaconsInProximity[0] : nil
displayOrSendNotification(isExiting: false, isBeacon: true)
}
}
}
}
}
Creating beacons to monitor:
var regionsToMonitor = [
BeaconData(uuid: UUID(uuidString: "82eee62a-b285-44dc-88e9-531188ee72e7")!, major: 0, minor: 1, name: "Dime Team", description: "Awesome Innovations", image: "beacon-icon"),
BeaconData(uuid: UUID(uuidString: "c2db97d9-6e80-44a2-82f5-3987065ba4ea")!, major: 7, minor: 11, name: "Data Team", description: "Busy Team", image: "beacon-icon")]
BeaconData Definition
struct BeaconData: RegionData{
let uuid: UUID
let major: NSNumber
let minor: NSNumber
let beaconRegion: CLBeaconRegion
let name: String
let detail: String
let image: String
init(uuid: UUID, major: NSNumber, minor: NSNumber, name: String, description: String, image: String) {
self.uuid = uuid
self.major = major
self.minor = minor
self.beaconRegion = CLBeaconRegion(beaconIdentityConstraint: CLBeaconIdentityConstraint(uuid: uuid), identifier: name)
self.name = name
self.detail = description
self.image = image
}
init(uuid: UUID, major: NSNumber, minor: NSNumber, beaconRegion: CLBeaconRegion, name: String, description: String, image: String) {
self.uuid = uuid
self.major = major
self.minor = minor
self.beaconRegion = beaconRegion
self.name = name
self.detail = description
self.image = image
}
func contains(region: CLRegion) -> Bool {
return self.beaconRegion == region
}
}
Here is the code to start ranging. Commented call on the bottom works as desired. Uncommented call above that is the wonky one. W create the constraint inline in the call, just the UUID. It works for one beacon, but as soon as we add a second (with different UUID as noted above) it only ranges the most recent.
for region in beaconRegionsToRange {
print("Start Ranging \(region.uuid)")
locationManager.startRangingBeacons(satisfying: CLBeaconIdentityConstraint(uuid: region.uuid))
//locationManager.startRangingBeacons(in: region)
}
How do we get it to range all beacons with the newer "satisfyingConstraints" method?
来源:https://stackoverflow.com/questions/60729509/swift-corelocation-ranging-beacons-using-clbeaconidentityconstraint-does-not