iosobjective-ccllocationmanageribeaconclbeaconregion

CLLocationManager requestStateForRegion with "When In Use" location access error code 4


I am trying to implement iBeacon ranging for an iOS app.

[locationManager requestAlwaysAuthorization];
CLBeaconRegion * region = [self regionFromUUID:uuid];
[locationManager startMonitoringForRegion:region];

In order to determine if the device is inside or outside of the region:

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
    [locationManager requestStateForRegion:region];
}

This successfully calls:

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
    if (state == CLRegionStateInside) {
        [locationManager startRangingBeaconsInRegion:(CLBeaconRegion*)region];
    } else {
        [locationManager stopRangingBeaconsInRegion:(CLBeaconRegion*)region];
    }
}

and the app is successfully on its way with locationManager:didRangeBeacons:inRegion:.

The problem I am encountering is using requestWhenInUseAuthorization. After locationManager:didStartMonitoringForRegion: calls [location requestStateForRegion:region], the delegate method locationManager:monitoringDidFailForRegion:withError: returns error code 4: "The operation couldn’t be completed".

Swapping requestStateForRegion with startRangingBeaconsInRegion seems to bypass this error and locationManager:didRangeBeacons:inRegion: is successfully called.

Is this a known issue that [locationManager requestStateForRegion:region]; will cause error code 4 if only kCLAuthorizationStatusAuthorizedWhenInUse is granted?


Solution

  • The Apple documentation for Region Monitoring was bothering me for this excerpt:

    If the authorization status is kCLAuthorizationStatusAuthorized, your app can receive boundary crossing notifications for any regions it registered. If the authorization status is set to any other value, the app doesn’t receive those notifications.

    I was thinking that kCLAuthorizationStatusAuthorized (deprecated in iOS 8) would include kCLAuthorizationStatusAuthorizedAlways and kCLAuthorizationStatusAuthorizedWhenInUse since they were both special types of "Authorized".

    Thanks to @heypiotr, I decided to actually look at the Apple Docs Declaration and noticed that the enum declares the follow:

    kCLAuthorizationStatusAuthorized,
    kCLAuthorizationStatusAuthorizedAlways = kCLAuthorizationStatusAuthorized,
    kCLAuthorizationStatusAuthorizedWhenInUse 
    

    So, requestStateForRegion requires kCLAuthorizationStatusAuthorizedAlways because that is the only value that is the same as kCLAuthorizationStatusAuthorized, and according to Apple, only kCLAuthorizationStatusAuthorized will work with monitoring.