2

I use the following code to check and request authorization for the Camera. Problem is the following. The following scenario leads to a wrong authorization status:

  1. User declines authorization for the first time
  2. Terminates the app
  3. Restarts the app
  4. Leaves the application, grants authorization for the camera in settings app
  5. Returns to the app

[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] will return AVAuthorizationStatusDeclined (authorized as said).

After terminating and restarting results in AVAuthorizationStatusAuthorized as it should. In this case the user leaves to settings and denies camera access the result will remain AVAuthorizationStatusAuthorized until next restart.

Any ideas what I miss here?

- (void) popCamera {
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.delegate = self;
    //picker.allowsEditing = YES;
    #if !(TARGET_IPHONE_SIMULATOR)
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;
    picker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
    #endif
    self.view.translatesAutoresizingMaskIntoConstraints = YES;
    [self presentViewController:picker animated:YES completion:NULL];
}

- (void)camDenied
{
    NSLog(@"%@", @"Denied camera access");

    NSString *alertText;
    NSString *alertButton;

    BOOL canOpenSettings = (&UIApplicationOpenSettingsURLString != NULL);
    if (canOpenSettings)
    {
        alertText = LSS(@"DeniedCamera1");

        SDCAlertView *alert = [[SDCAlertView alloc]
                              initWithTitle:LSS(@"DeniedCameraTitle")
                              message:alertText
                              delegate:self
                              cancelButtonTitle:LSS(@"Cancel")
                              otherButtonTitles:LSS(@"Goto"), nil];
        alert.tag = 3491832;
        [alert show];
    }
    else
    {
        alertText = LSS(@"DeniedCamera2");

        SDCAlertView *alert = [[SDCAlertView alloc]
                              initWithTitle:LSS(@"DeniedCameraTitle")
                              message:alertText
                              delegate:self
                              cancelButtonTitle:LSS(@"Cancel")
                              otherButtonTitles:nil];
        alert.tag = 3491832;
        [alert show];
    }

}

- (IBAction) onTakePhoto:(id)sender {
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if(authStatus == AVAuthorizationStatusAuthorized)
    {
        [self popCamera];
    }
    else if(authStatus == AVAuthorizationStatusNotDetermined)
    {
        NSLog(@"%@", @"Camera access not determined. Ask for permission.");

        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted)
         {
             if(granted)
             {
                 [self popCamera];
             }
             else
             {
                 [self camDenied];
             }
         }];
    }
    else if (authStatus == AVAuthorizationStatusRestricted)
    {
        SDCAlertView *alert = [[SDCAlertView alloc]
                              initWithTitle:LSS(@"RestrictCameraTitle")
                              message:LSS(@"RestrictCamera")
                              delegate:self
                              cancelButtonTitle:LSS(@"OK")
                              otherButtonTitles:nil];
    }
    else
    {
        [self camDenied];
    }

    }

Credits for the original code: Is there a way to ask user for Camera access after they have already denied it on iOS 8?

Community
  • 1
  • 1
Teddy
  • 1,056
  • 1
  • 14
  • 24
  • I don't really understand. 1) User denies access. 2) App is terminated. 3) User grants access in settings. 4) App gets authorized status when started again. So far, so good, that's correct. But I don't understand what's happens next that you consider wrong. Do you mean the user then goes to the settings and denies access _while the app is running_ and it doesn't affect the current session? – DarkDust Dec 28 '15 at 18:52
  • Yes I mean that. User denies => terminates app => restarts app => leaves app in background (multitask) => goes to Settings App and changes authorization => returns to App (ie: back button in top left corner) => Status remains "Denied" reported by authorizationStatusForMediaType (yet camera works as it should) => Terminates app => Restarts app => Status Accepted. And vice-versa. Seems that the authorization won't get updated. – Teddy Dec 28 '15 at 22:51

1 Answers1

0

This seems to be the intended behaviour. If Apple would want you to react to authorization changes at runtime, there would be a notification that tells you that it changed.

But right now, there is no such notification (as far as I can see). You just call +authorizationStatusForMediaType: and it either returns a definitive status (like denied or authorized), or it returns AVAuthorizationStatusNotDetermined to tell you that you need to request authorization via requestAccessForMediaType:completionHandler:.

Unfortunately, this isn't an authoritative answer; I'm just drawing conclusions and guessing here. You might want to ask on Apple's developer forum and hope to get an answer from an Apple engineer.

DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • I understand there is no such notification. But when I query with +authorizationStatusForMediaType: it should return the correct status. Why do I need a restart of the App to detect the status correctly? – Teddy Dec 28 '15 at 23:08
  • Maybe it's caching the value and doesn't know the actual authorization changed. Since there is no way to get informed about such an authorization change, IMHO it's good that the value is stable throughout the whole session: otherwise you would need to query the status all the time. Since I haven't tested it: I guess if the method returns `AVAuthorizationStatusAuthorized`, you _are_ able to access the camera even if the user changed the setting? – DarkDust Dec 28 '15 at 23:17
  • Yes but this is so inconsistent. Ie: compare with location services. You grant the authorization and it is recognised by the app. What makes this very disturbing is that the user will see a Black screen instead of receiving a proper error message. – Teddy Dec 28 '15 at 23:20
  • Aha, so even though you get `AVAuthorizationStatusAuthorized`, you cannot really access the camera any more? Then it really is inconsistent. I suggest you file a bugreport with Apple for this. – DarkDust Dec 28 '15 at 23:23
  • Correct. And vice-versa (yet this scenario is quite unlikely, that the user declines manually then returns to the app). When it is reported to be denied I can access the camera. Any change while the app is running generates an incorrect status. – Teddy Dec 28 '15 at 23:26
  • 2
    The issue has been solved: when I wont debug it will terminate the app. When I debug it throws an exception but I can continue the app. Strange but at least not confusing for the user. – Teddy Dec 28 '15 at 23:42