Requesting Location Services in iOS 8

iOS 8 has changed how location services are handled. First, there are two levels of location monitoring now allowed. From the Apple Docs on CLLocationManager:

  • kCLAuthorizationStatusAuthorizedAlways
    • This is the exact same as kCLAuthorizationStatusAuthorizedAlways in iOS 7. Your app can register to monitor regions and significant location changes, and it can actually launch itself in response to these events!
  • kCLAuthorizationStatusAuthorizedWhenInUse
    • This is new in iOS 8, and it’s a restricted level of authorization that only allows your app to access location services when it’s running in the foreground. It does not allow region monitoring and significant location changes.

Previously, apps could ask the user for authorization by starting to use location services in your app:

self.locationManager = [[CLLocationManager alloc] init];
// This should open an alert that prompts the user, but in iOS 8 it doesn't!
[self.locationManager startUpdatingLocation];

Now, it does nothing.

Here are the steps to getting your app back to its former glory:

  1. If your app needs kCLAuthorizationStatusAuthorizedAlways, go to your app’s info.plist and add the NSLocationAlwaysUsageDescription key: Screen Shot 2014-09-18 at 3.28.13 PM 
  2. If your app needs kCLAuthorizationStatusAuthorizedWhenInUse, go to your app’s info.plist and add the NSLocationWhenInUseUsageDescription key:
    Screen Shot 2014-09-18 at 3.32.52 PM
  3. Add a description to this key that describes why your app is requesting for location services. This is a really good practice to explain to users why they should give you permission. If you don’t provide any context to this, your users will tend to be distrustful of you invading their privacy!
  4. In your app, request for permissions:
        // iOS 8 - request location services via requestWhenInUseAuthorization.
        if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
            [self.locationManager requestWhenInUseAuthorization];
        } else {
            // iOS 7 - We can't use requestWhenInUseAuthorization -- we'll get an unknown selector crash!
            // Instead, you just start updating location, and the OS will take care of prompting the user
            // for permissions.
            [self.locationManager startUpdatingLocation];
        }
    
  5. Implement the delegate method that alerts you when the user has accepted permissions.
    - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
    {
        // We only need to start updating location for iOS 8 -- iOS 7 users should have already
        // started getting location updates
        if (status == kCLAuthorizationStatusAuthorizedAlways ||
            status == kCLAuthorizationStatusAuthorizedWhenInUse) {
            [manager startUpdatingLocation];
        }
    }

The workflow works like this:

  • Your app makes a call to requestWhenInUseAuthorization if it’s available (in iOS 8), or it uses the old iOS 7 method to maintain backwards support.
  • requestWhenInUseAuthorization displays an alert-style dialog if your app’s info.plist includes the NSLocationWhenInUseDescription or NSLocationAlwaysUsageDescription. The dialog has the text value from the plist. (See Localizing Property List Values to localize your info.plist strings.)
  • If the user declines, the CLLocationManager status becomes kCLAuthorizationStatusDenied. If the user accepts, the CLLocationManager status becomes kCLAuthorizationStatusAuthorizedAlways|WhenInUse.
  • The CLLocationManagerDelegate receives a message when the status changes, which is a great place to kick off location monitoring. Since the request/accept is asychronous, you can’t start monitoring until you’re certain that the user has accepted.

Leave a Reply

Your email address will not be published. Required fields are marked *