ios 在iOS中检测相机的权限

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20464631/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:41:12  来源:igfitidea点击:

Detect permission of camera in iOS

iospermissionscamerauiimagepickercontrollerios-permissions

提问by user418751

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

我正在开发一个非常简单的视频应用程序。我使用官方控件: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.

这是问题所在。当第一次呈现 UIImagePickerController 时,iOS 会请求许可。用户可以单击是或否。如果用户单击“否”,则不会解除控件。相反,如果用户一直单击开始按钮,计时器会继续运行,而屏幕始终是黑色的,并且用户无法停止计时器或返回。用户唯一能做的就是杀死应用程序。下一次出现 UIImagePickerController 时,还是黑屏,点击开始就回不去了。

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?

我想知道这是不是一个错误。有什么方法可以检测相机的权限,以便我们可以决定是否显示 UIImagePickerController?

回答by Raptor

Check the AVAuthorizationStatusand handle the cases properly.

检查AVAuthorizationStatus并妥善处理案件。

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
}

回答by Nikita Kukushkin

Swift 4 and newer

Swift 4 及更新版本

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 NSCameraUsageDescriptionkey in your Info.plist to be able ask for camera access, otherwise your app will crash at runtime. See APIs Requiring Usage Descriptions.

从 iOS 10 开始,您需要NSCameraUsageDescription在 Info.plist 中指定 key 才能请求相机访问,否则您的应用程序将在运行时崩溃。请参阅需要使用说明的 API



As an interesting side note, did you know that iOS kills the app if it's running while you change its camera permissions in Settings?

作为一个有趣的旁注,您是否知道当您在“设置”中更改其相机权限时,iOS 会杀死正在运行的应用程序?

From Apple Developer forum:

来自苹果开发者论坛:

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

如果用户在“设置”中切换您的应用程序对相机的访问权限,系统实际上会终止您的应用程序。这同样适用于设置→隐私部分中的任何受保护数据类。

回答by Josh Bernfeld

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
})

回答by Bart van Kuik

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.

作为@Raptor 答案的补充,应提及以下内容。从 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):

要解决此问题,请确保按如下方式处理主线程的结果(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
                }
            }
        }
    }
}

回答by Yogendra Singh

Specify NSCameraUsageDescription key in Info.plist first. Then check AVAuthorizationStatus if Authorised then present the UIImagePickerController. It will work.

首先在 Info.plist 中指定 NSCameraUsageDescription 键。然后检查 AVAuthorizationStatus 如果已授权,则显示 UIImagePickerController。它会起作用。

回答by A.G

Swift: Using AVFoundation

Swift:使用 AVFoundation

  1. Add AVFoundation to Target -> Build Phases -> Link Binary with Libraries.
  2. import AVFoundation on ViewController.
  3. On Info.plist, Add the following:
  1. 将 AVFoundation 添加到 Target -> Build Phases -> Link Binary with Libraries。
  2. 在 ViewController 上导入 AVFoundation。
  3. 在 Info.plist 上,添加以下内容:

enter image description here

在此处输入图片说明

  1. On View Controller:
  1. 在视图控制器上:

@IBAction func cameraButtonClicked(sender: AnyObject) {

@IBAction func cameraButtonClicked(sender: AnyObject) {

let authorizationStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)
print(authorizationStatus.rawValue)

if AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) ==  AVAuthorizationStatus.Authorized{
    self.openCameraAfterAccessGrantedByUser()
}
else
{
    print("No Access")

    dispatch_async(dispatch_get_main_queue()) { [unowned self] in
        AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (granted :Bool) -> Void in
            if granted == true
            {
                // User granted
                self.openCameraAfterAccessGrantedByUser()
            }
            else
            {
                // User Rejected
                  alertToEncourageCameraAccessWhenApplicationStarts()
            }
        });
    }
}


//Open camera

    func openCameraAfterAccessGrantedByUser()
    {
    if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera)){
        self.cameraAndGalleryPicker!.sourceType = UIImagePickerControllerSourceType.Camera
        cameraAndGalleryPicker?.delegate = self
        cameraAndGalleryPicker?.allowsEditing =  false
        cameraAndGalleryPicker!.cameraCaptureMode = .Photo
        cameraAndGalleryPicker!.modalPresentationStyle = .FullScreen
        presentViewController(self.cameraAndGalleryPicker!, animated: true, completion: nil)
    }
    else
    {

    }
}

//Show Camera Unavailable Alert

func alertToEncourageCameraAccessWhenApplicationStarts()
    {
        //Camera not available - Alert
        let cameraUnavailableAlertController = UIAlertController (title: "Camera Unavailable", message: "Please check to see if it is disconnected or in use by another application", preferredStyle: .Alert)

let settingsAction = UIAlertAction(title: "Settings", style: .Destructive) { (_) -> Void in
    let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
    if let url = settingsUrl {
        dispatch_async(dispatch_get_main_queue()) {
            UIApplication.sharedApplication().openURL(url)
        }

    }
}
let cancelAction = UIAlertAction(title: "Okay", style: .Default, handler: nil)
cameraUnavailableAlertController .addAction(settingsAction)
cameraUnavailableAlertController .addAction(cancelAction)
self.window?.rootViewController!.presentViewController(cameraUnavailableAlertController , animated: true, completion: nil)
}