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?

sschale
  • 5,168
  • 3
  • 29
  • 36
n8yn8
  • 4,467
  • 4
  • 19
  • 20
  • Is background refresh *disabled* for your app? – Aaron Mar 17 '16 at 23:44
  • It is not disabled. Under `Capabilities`, `Background Modes`, I have `Location Updates` checked. On the device, under `General` > `Background App Refresh`, Background App Refresh is generally enabled. This error occurs when the app is in the foreground though. – n8yn8 Mar 17 '16 at 23:50
  • Shootin' the dark now, but have you tried calling `+requestWhenInUseAuthorization` just for giggles? – Aaron Mar 18 '16 at 01:59
  • Yup, tried requesting WhenInUse. It seems to be specifically on requestStateForRegion that the error occurs – n8yn8 Mar 18 '16 at 02:34
  • Ah, crud. I meant to ask have you tried `+requestAlwaysAuthorization`? You mentioned `+requestInWhenInUseAuthorization` in your post. – Aaron Mar 18 '16 at 13:20
  • Yup, tried that too. – n8yn8 Mar 18 '16 at 13:30

2 Answers2

4

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.

n8yn8
  • 4,467
  • 4
  • 19
  • 20
1

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.

heypiotr
  • 2,139
  • 2
  • 15
  • 22
  • It wasn't making sense why Apple Docs say `kCLAuthorizationStatusAuthorized` is required but the special type of "Authorized" of `kCLAuthorizationStatusAuthorizedAlways` and `kCLAuthorizationStatusAuthorizedWhenInUse` were not synonymous to the deprecated `kCLAuthorizationStatusAuthorized`. I think I found the root of the problem in my answer. – n8yn8 Mar 21 '16 at 21:51