在iOS中检测相机的权限


143

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

这是问题所在。首次显示UIImagePickerController时,iOS将请求权限。用户可以单击“是”或“否”。如果用户单击否,则不会关闭该控件。相反,如果用户一直单击“开始”按钮,则计时器将在屏幕始终为黑屏时继续运行,并且用户无法停止计时器或返回计时器。用户唯一能做的就是杀死该应用程序。下次呈现UIImagePickerController时,它仍然是黑屏,并且如果单击开始,则用户无法返回。

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


回复:这是一个错误吗?恕我直言,我认为是这样,因为似乎发生的是VC正在显示硬件中的数据,但是OS基本上在发送死气。iOS如何到达这里可能是产品家族演变的副作用。UIImageViewController标记为在iOS 2.0中添加的,并且该文档从未进行注释以反映应使用AVAuthorizationStatus,但存在于另一个框架中。
benc

Answers:


229

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

19
还需要:#import <AVFoundation/AVFoundation.h>或类似
toblerpwn 2014年

9
可能有用的提示-如果您正在测试使用此功能的代码,则不能仅从测试设备中删除您的App,然后重新安装。这样做不会导致iOS重新向用户发出请求!不过,对我有用的是Bundle ID每次我要对此进行测试时都要更改应用程序的功能。流浪汉疼痛,但至少有一点。只记得完成操作后将ID设置回来;-)
Benjohn 2014年

25
@Benjohn:不需要更改Bundle ID。您可以转到设置>常规>重置,然后找到一个设置,该设置将重置设备上的所有权限提示。当然,这也很烦人,因为它也会影响设备上的所有其他应用程序。如果只有Apple可以在Settings.app ...的“开发”部分中为此添加特定于应用程序的控件
KennyDeriemaeker 2014年

3
@KennyDeriemaeker :-)苹果可能会回答我们应该使用专用设备进行测试!对我来说,重置我的常规手机会带来很多麻烦。更改捆绑包ID是相当合理的选择。我记得在提交之前也将其改回了:-)
Benjohn 2014年

8
只要确保您没有完全重置即可!只需重置“隐私和位置”设置(iOS 8)就足够了。
Canucklesandwich

81

Swift 4及更高版本

确保:

import AVFoundation

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

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

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


作为一个有趣的旁注,您是否知道在设置中更改其摄像头权限时,如果iOS正在运行,iOS会终止该应用程序?

从Apple Developer论坛:

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


授权照相机和照相馆怎么样?
哈哈尔·艾尔库米基

4

快速解决方案

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

然后为了使用它

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

授权照相机和照相馆怎么样?
哈哈尔·埃尔科米基

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

如果被拒绝,则requestAccess方法将不起作用。您将必须手动显示警报,以要求用户进入设置并授予权限。
阿卜杜拉·乌默尔

0

首先在Info.plist中指定NSCameraUsageDescription键。然后检查AVAuthorizationStatus是否已授权,然后显示UIImagePickerController。会的。


-4

Swift:使用AVFoundation

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

在此处输入图片说明

  1. 在View Controller上:

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

什么是Info.plist条目?资源?
条例草案
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.