Open Settings URL

A quick tip I picked up from WWDC 2014 session 715 on User Privacy. Starting with iOS 8 there is now a settings launch URL to send the user directly to the settings for an App. The code snippet below will do the trick:

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:
 UIApplicationOpenSettingsURLString]];

Updating Privacy Settings

As an example of where the settings URL can be useful I thought I would go back and update the QR Reader project to better handle the camera privacy settings. See the original post on reading QR codes for the full details. In brief the setup of the camera capture session involves the creation of an input capture device:

NSError *error = nil;
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];

The creation of the AVCaptureDeviceInput can fail if the device does not have a suitable camera or if the user refuses to allow access. In iOS 7 asking the user for permission to access the camera was region dependent. The camera privacy settings changed in iOS 8 to be globally consistent and always ask the user the first time an application tries to access the camera:

In the original code I did not spend any time handling failures. This is especially unhelpful as the user is only prompted to allow access the first time. I will fix that now by adding a method showAlertForCameraError: to give the user some feedback when we fail to create the input capture device:

if (deviceInput) {
  // Device access allowed
} else {
  // Device access failed
  [self showAlertForCameraError:error];
}

Show Alert For Camera Error

The NSError object returned when the deviceInputWithDevice:error: method fails gives us all we need to understand the cause of the failure. If the error code is AVErrorApplicationIsNotAuthorizedToUseDevice we know that the user refused to give us permission.

The idea is to show the user an alert with the error message and for a permissions problem allow the user to jump straight to the app settings to change the privacy settings. The code to check the error type and show an alert view is below:

- (void)showAlertForCameraError:(NSError *)error {
  NSString *buttonTitle = nil;
  NSString *message = error.localizedFailureReason ?
   error.localizedFailureReason : error.localizedDescription;

  if ((error.code == AVErrorApplicationIsNotAuthorizedToUseDevice) &&
      UIApplicationOpenSettingsURLString) {
    buttonTitle = NSLocalizedString(@"AlertViewSettingsButton", @"Settings");
  }

  UIAlertView *alertView = [[UIAlertView alloc]
    initWithTitle:NSLocalizedString(@"AlertViewTitleCameraError", @"Camera Error")
            message:message
           delegate:self
  cancelButtonTitle:NSLocalizedString(@"AlertViewCancelButton", @"Cancel")
  otherButtonTitles:buttonTitle, nil];
  [alertView show];
}

Notes:

  • The NSError object gives us a localized error message which we can show in the alert view. If present I use localizedFailureReason which at least for camera failures seems to more user-friendly. The fallback is to use localizedDescription.
  • We only want to add the Settings button for permission problems if the launch URL is supported, which is not the case for iOS 7, so we check the URL string is not nil.
  • Finally we create and show the alert view with the view controller as the alert view delegate.

Sending the User to Settings

With the view controller set as the UIAlertView delegate we can handle the user “clicking” the settings button by launching the settings URL:

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
  if (buttonIndex == 1) {
    NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
    [[UIApplication sharedApplication] openURL:url];
  }
}

The result is to launch the settings app and open the application specific settings page:

Wrapping Up

I have posted the updated sample code to my GitHub code examples repository if you want to take a closer look.