Detect permission of camera in iOS

93,232

Solution 1

Check the AVAuthorizationStatus and handle the cases properly.

NSString *mediaType = AVMediaTypeVideo;
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
if(authStatus == AVAuthorizationStatusAuthorized) {
  // do your logic
} else if(authStatus == AVAuthorizationStatusDenied){
  // denied
} else if(authStatus == AVAuthorizationStatusRestricted){
  // restricted, normally won't happen
} else if(authStatus == AVAuthorizationStatusNotDetermined){
  // not determined?!
  [AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
    if(granted){
      NSLog(@"Granted access to %@", mediaType);
    } else {
      NSLog(@"Not granted access to %@", mediaType);
    }
  }];
} else {
  // impossible, unknown authorization status
}

Solution 2

Swift 4 and newer

Make sure to:

import AVFoundation

The code below checks for all possible permission states:

let cameraMediaType = AVMediaType.video
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: cameraMediaType)
    
switch cameraAuthorizationStatus {
case .denied: break
case .authorized: break
case .restricted: break

case .notDetermined:
    // Prompting user for the permission to use the camera.
    AVCaptureDevice.requestAccess(for: cameraMediaType) { granted in
        if granted {
            print("Granted access to \(cameraMediaType)")
        } else {
            print("Denied access to \(cameraMediaType)")
        }
    }
}

Since iOS 10 you need to specify NSCameraUsageDescription key in your Info.plist to be able ask for camera access, otherwise your app will crash at runtime. See APIs Requiring Usage Descriptions.


An interesting sidenote from Apple Developer forum:

The system actually kills your app if the user toggles your app's access to camera in Settings. The same applies to any protected dataclass in the Settings→Privacy section.

Solution 3

Swift Solution

extension AVCaptureDevice {
    enum AuthorizationStatus {
        case justDenied
        case alreadyDenied
        case restricted
        case justAuthorized
        case alreadyAuthorized
        case unknown
    }

    class func authorizeVideo(completion: ((AuthorizationStatus) -> Void)?) {
        AVCaptureDevice.authorize(mediaType: AVMediaType.video, completion: completion)
    }

    class func authorizeAudio(completion: ((AuthorizationStatus) -> Void)?) {
        AVCaptureDevice.authorize(mediaType: AVMediaType.audio, completion: completion)
    }

    private class func authorize(mediaType: AVMediaType, completion: ((AuthorizationStatus) -> Void)?) {
        let status = AVCaptureDevice.authorizationStatus(for: mediaType)
        switch status {
        case .authorized:
            completion?(.alreadyAuthorized)
        case .denied:
            completion?(.alreadyDenied)
        case .restricted:
            completion?(.restricted)
        case .notDetermined:
            AVCaptureDevice.requestAccess(for: mediaType, completionHandler: { (granted) in
                DispatchQueue.main.async {
                    if granted {
                        completion?(.justAuthorized)
                    } else {
                        completion?(.justDenied)
                    }
                }
            })
        @unknown default:
            completion?(.unknown)
        }
    }
}

And then in order to use it you do

AVCaptureDevice.authorizeVideo(completion: { (status) in
   //Your work here
})

Solution 4

As an addition to the answer from @Raptor the following should be mentioned. You may receive the following error starting with iOS 10: This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.

To fix this, make sure you handle the results from the main thread as follows (Swift 3):

private func showCameraPermissionPopup() {
    let cameraMediaType = AVMediaTypeVideo
    let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: cameraMediaType)

    switch cameraAuthorizationStatus {
    case .denied:
        NSLog("cameraAuthorizationStatus=denied")
        break
    case .authorized:
        NSLog("cameraAuthorizationStatus=authorized")
        break
    case .restricted:
        NSLog("cameraAuthorizationStatus=restricted")
        break
    case .notDetermined:
        NSLog("cameraAuthorizationStatus=notDetermined")

        // Prompting user for the permission to use the camera.
        AVCaptureDevice.requestAccess(forMediaType: cameraMediaType) { granted in
            DispatchQueue.main.sync {
                if granted {
                    // do something
                } else {
                    // do something else
                }
            }
        }
    }
}
Share:
93,232

Related videos on Youtube

user418751
Author by

user418751

Updated on September 22, 2021

Comments

  • user418751
    user418751 over 2 years

    I am developing a very simple video app. I use the official control: UIImagePickerController.

    Here is the problem. When presenting the UIImagePickerController for the first time, the iOS will ask for the permission. The user can click yes or no. If the user clicks no, the control is not dismissed. Instead, if the user keeps clicking the start button, the timers go on while the screen is always black, and the user can't stop the timers or go back. The only thing the user can do is to kill the app. The next time the UIImagePickerController is presented, it is still a black screen and the user can't go back if clicking start.

    I was wondering if it's a bug. Is there any way we can detect the permission of the camera so that we can decide to show the UIImagePickerController or not?

    • benc
      benc almost 4 years
      Re: is it a bug? IMHO, I think so, because what appears to happen is that the VC is displaying the data from the hardware, but the OS is basically sending dead air. How iOS got here is probably a side effect of the evolution of the product family. UIImageViewController is noted as being added in iOS 2.0, and the docs never annotated to reflect that the AVAuthorizationStatus should be used, but lives in another framework.
    • ch271828n
      ch271828n over 3 years
      Apple seems to have a official tutorial here: developer.apple.com/documentation/avfoundation/…
  • toblerpwn
    toblerpwn over 9 years
    also requires: #import <AVFoundation/AVFoundation.h> or similar
  • Raptor
    Raptor over 9 years
    Yes. Requires to import AVFoundation.h. (p.s. the above script is also valid in iOS 8)
  • Benjohn
    Benjohn over 9 years
    A possibly useful tip – if you are testing code that uses this, you can't merely delete your App from the testing device and then re-instal. Doing this will not cause iOS to reissue the request to the user! What's worked for me though is to change the Bundle ID of the app each time I want to test this. A pain in the bum, but something, at least. Just remember to set the ID back when you are finished ;-)
  • KennyDeriemaeker
    KennyDeriemaeker over 9 years
    @Benjohn: changing Bundle ID is unnecessary. You can go to Settings > General > Reset and find a setting that will reset all permission prompts on the device. Granted, that's also annoying as it affects all the other apps on your device as well. If only Apple could add apps-specific controls for this in the Development section of Settings.app...
  • Benjohn
    Benjohn over 9 years
    @KennyDeriemaeker :-) Apple might reply that we're supposed to used dedicated devices for testing! For me the side effects of resetting my regular phone would have been pretty sucky. Changing the bundle Id was a reasonably painless alternative. I remembered to change it back before submission too :-)
  • Canucklesandwich
    Canucklesandwich almost 9 years
    Just make sure you don't do a full reset! Simply resetting the Privacy & Location settings (iOS 8) will suffice.
  • Supertecnoboff
    Supertecnoboff over 8 years
    This is an awesome answer. Can this be used to check if the user has granted photo library access too?
  • Raptor
    Raptor over 8 years
    @Supertecnoboff check this out: stackoverflow.com/questions/15004114/…
  • Supertecnoboff
    Supertecnoboff over 8 years
    @Raptor Thanks, but I can't use that. ALAssetsLibrary is deprecated as of iOS 9.
  • Supertecnoboff
    Supertecnoboff over 8 years
    @Raptor No matter, I figured it out using PHPhotoLibrary: stackoverflow.com/a/32989022/1598906
  • Bill
    Bill over 7 years
    What's with the Info.plist entries? Source?
  • Ethan Allen
    Ethan Allen about 6 years
    If a user denies camera access and you want to request that they change their permissions to allow it (by taking them directly to Settings) see this: stackoverflow.com/questions/26070393/…
  • Abdullah Umer
    Abdullah Umer about 5 years
    In case of denied, the requestAccess method will not work. You will have to manually show an alert to ask the user to go to settings and grant permissions.
  • Hajar ELKOUMIKHI
    Hajar ELKOUMIKHI about 4 years
    What about authorizing camera and photo gallery ??
  • Hajar ELKOUMIKHI
    Hajar ELKOUMIKHI about 4 years
    What about authorizing camera and photo gallery ??