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

1.5k Views Asked by At

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?

2

There are 2 best solutions below

0
n8yn8 On BEST ANSWER

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.

1
heypiotr On

Core Location monitoring requires the "always" authorization, even if you're only trying to do monitoring when the app is active. Since requestStateForRegion is part of the monitoring API, it'd explain why it throws the monitoring error when on the "when in use" authorization.

The only workaround I can think of is, when on the "when in use" authorization, start ranging right away and use ranging results instead of requestStateForRegion to determine whether you're inside or outside range of a given beacon.