在iOS中检测摄像头的权限

时间:2013-12-09 06:40:11

标签: ios permissions camera uiimagepickercontroller ios-permissions

我正在开发一个非常简单的视频应用。我使用官方控件:UIImagePickerController。

这是问题所在。在第一次展示UIImagePickerController时,iOS会要求获得许可。用户可以单击是或否。如果用户单击否,则不会解除控件。相反,如果用户一直点击开始按钮,则计时器继续亮起,而屏幕始终为黑色,用户无法停止计时器或返回。用户唯一能做的就是杀死应用程序。下次呈现UIImagePickerController时,它仍然是黑屏,如果单击开始,用户将无法返回。

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

6 个答案:

答案 0 :(得分:217)

检查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
}

答案 1 :(得分:73)

从iOS 10开始,您需要指定 您的Info.plist中的NSCameraUsageDescription键可以请求摄像头访问,否则您的应用程序将在运行时崩溃。请参阅APIs Requiring Usage Descriptions

请务必:

import AVFoundation

下面的 Swift 代码会检查所有可能的权限状态:

Swift 4和更新

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

Swift 3

let cameraMediaType = AVMediaTypeVideo
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: 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(forMediaType: cameraMediaType) { granted in
        if granted {
            print("Granted access to \(cameraMediaType)")
        } else {
            print("Denied access to \(cameraMediaType)")
        }
    }
}

作为一个有趣的旁注,你是否知道如果你在设置中更改其相机权限时iOS正在运行该应用程序?

来自Apple Developer论坛:

  

如果用户切换您的应用,系统会实际杀死您的应用   访问“设置”中的摄像头。这同样适用于任何受保护的   设置→隐私部分中的数据类。

答案 2 :(得分:2)

作为@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.

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

答案 3 :(得分:2)

Swift Solution

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

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

然后为了使用它你做

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

答案 4 :(得分:0)

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

答案 5 :(得分:-5)

Swift:使用AVFoundation

  1. 将AVFoundation添加到目标 - >构建阶段 - > Link Binary与Libraries。
  2. 在ViewController上导入AVFoundation。
  3. 在Info.plist上,添加以下内容:
  4. enter image description here

    1. 在视图控制器上:
    2. @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)
      }