1
votes

Apple has really simplified how you can receive location based notifications in iOS 10, however, I'm finding that when the notification gets triggered and the UNUserNotificationCenterDelegate delegate methods get called, the region objects that come down have the major and minor values always set to null. So when the delegate method for receiving the notification when the app is in the foreground, this method gets called:

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    // When the app is in the foreground
    if let trigger = notification.request.trigger as? UNLocationNotificationTrigger, 
                                          let region = trigger.region as? CLBeaconRegion {
        // When you examine the region variable here, its major and minor
        // values are null
    }

    completionHandler([.alert, .sound])
}

The CLBeaconRegion object's major and minor NSNumber variables are always null. I tell the CLLocationManager to range for beacons, which should provide these values, shouldn't it? Any idea what's missing here? Or is this by design? I get the same result regardless of whether it's an actual beacon (e.g. KST particle) or another iOS device broadcasting over bluetooth using a CBPeripheralManager.

Here's my notification registration code:

let locationManager = CLLocationManager()

func createLocationNotification() {
    self.locationManager.requestWhenInUseAuthorization()

    let region = CLBeaconRegion(proximityUUID: UUID(uuidString: "UUID-STRING")!, identifier: "com.company.identifier")
    region.notifyOnEntry = true
    region.notifyOnExit = false

    let content = UNMutableNotificationContent()
    content.title = "New Checkin Received"
    content.body = "Swipe or tap this message to see who's here"

    let trigger = UNLocationNotificationTrigger(region: region, repeats: true)
    let request = UNNotificationRequest.init(identifier: "BeaconNotificationIdentifier", content: content, trigger: trigger)

    UNUserNotificationCenter.current().delegate = self
    UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in

    })

    self.locationManager.startRangingBeacons(in: region)
}
1
I would image that the CLBeaconRegion that is passed to the delegate is the same region that you registered with the UNLocationNotificationTrigger. Since this didn't have a major or minor, you don't have a major or minor in the delegate. You should start ranging beacons in the notification delegate method and then work out from didRangeBeacon the major and minor.Paulw11

1 Answers

1
votes

The UNLocationNotificationTrigger is a convenience wrapper around beacon monitoring APIs, not beacon ranging APIs. Monitoring APIs simply do not report the individual identifiers detected, only the CLBeaconRegion used as the pattern filter to set up monitoring. You can't use monitoring to figure out the exact identifier detected.

This makes sense if you look at how the API works. UNLocationNotificationTrigger has a property of region which is a CLRegion. It does not have a CLBeacon property, which it would have to in order to detect the individual identifiers. While it is possible to have a CLBeaconRegion that has the identifiers fully populated, if iOS were behaving the way you'd like, it would have had to construct a new CLRegion instance in order to populate its fields with the specific beacon identifiers detected.

Unfortunately, the alternative, as @Paulw11 suggests in his comment is to not use this convenience wrapper and use beacon ranging to trigger your notifications manually.