在iOS 8中显示摄像头权限对话框


73

当我的应用首次尝试在iOS 8上访问摄像头时,会向用户显示一个摄像头许可对话框,就像在iOS 7中访问麦克风的麦克风一样。

在iOS 7中,可以事先调用麦克风权限对话框,并查看是否已授予该权限(例如,请参阅此问题)。在iOS 8中,有没有类似的方法可以调用相机权限对话框?对话框可以组合使用以获取麦克风和摄像头访问权限吗?


刚刚发布了一个答案,该答案同时检查了摄像头和麦克风的访问权限,并捕获了授予摄像头权限但未授予麦克风权限的场景。
Crashalot

Answers:


90

这是我们最终使用的方法:

if ([AVCaptureDevice respondsToSelector:@selector(requestAccessForMediaType: completionHandler:)]) {
    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
        // Will get here on both iOS 7 & 8 even though camera permissions weren't required 
        // until iOS 8. So for iOS 7 permission will always be granted.
        if (granted) {
            // Permission has been granted. Use dispatch_async for any UI updating
            // code because this block may be executed in a thread.
            dispatch_async(dispatch_get_main_queue(), ^{
                [self doStuff];
            });                
        } else {
            // Permission has been denied.
        }
    }];
} else {
    // We are on iOS <= 6. Just do what we need to do.
    [self doStuff];
}

4
一条小注释-iOS 7中也存在requestAccessForMediaType方法(当时仅在某些区域内,iOS才要求获得相机许可)。所以else部分适用于<6的iOS
尼拉吉

2
经过我自己的测试,将代码注释更新为更具信息性/正确性。
特纳2015年

在我们的测试中,此代码未捕获授予摄像机权限但拒绝话筒权限的情况。
Crashalot

2
此代码仅适用于相机权限,这是原始问题的主题。
jamix

2
对于iOS 10或更高版本,别忘了将NSCameraUsageDescription放在您的plist中-以及寻求许可的目的。如果不这样做,它将崩溃。
Jordan Hochstetler'3

62

我遇到了类似的问题,如果用户在首次提示时拒绝了相机访问权限,则在相机模式下,按下按钮进行快照会导致黑屏。

但是,我想检测到用户已拒绝访问,并提示他们必须将其打开,但是我找不到任何功能来检查当前用户的摄像机访问权限,是否有这样的功能?

编辑:以下检查将使您在IOS 8中了解有关摄像机访问的信息:

#import <AVFoundation/AVFoundation.h>

AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

    if(status == AVAuthorizationStatusAuthorized) { // authorized

    }
    else if(status == AVAuthorizationStatusDenied){ // denied

    }
    else if(status == AVAuthorizationStatusRestricted){ // restricted


    }
    else if(status == AVAuthorizationStatusNotDetermined){ // not determined

        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            if(granted){ // Access has been granted ..do something

            } else { // Access denied ..do something

            }
        }];
    }

在以下问题上找到了此信息(如何知道应用程序是否具有相机访问权限,而在iOS8中不是以编程方式访问的):


53

这是我的Swift解决方案(iOS 8),我需要相机进行QR扫描,因此确实必须提示其使用。

这提供

  1. 鼓励用户在默认允许摄像机访问问题之前选择允许

  2. 如果用户拒绝了第一个请求,则访问设置的简便方法。

要使其运行,请在ViewDidAppear /或ViewDidLoad等中检查相机。我需要使用viewDidAppear,以便设置我的自定义相机视图约束。

func checkCamera() {
    let authStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
    switch authStatus {
    case .authorized: break // Do your stuff here i.e. allowScanning()
    case .denied: alertToEncourageCameraAccessInitially()
    case .notDetermined: alertPromptToAllowCameraAccessViaSetting()
    default: alertToEncourageCameraAccessInitially()
    }
}

func alertToEncourageCameraAccessInitially() {
    let alert = UIAlertController(
        title: "IMPORTANT",
        message: "Camera access required for QR Scanning",
        preferredStyle: UIAlertControllerStyle.alert
    )
    alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
    alert.addAction(UIAlertAction(title: "Allow Camera", style: .cancel, handler: { (alert) -> Void in
        UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!)
    }))
    present(alert, animated: true, completion: nil)
}

func alertPromptToAllowCameraAccessViaSetting() {

    let alert = UIAlertController(
        title: "IMPORTANT",
        message: "Please allow camera access for QR Scanning",
        preferredStyle: UIAlertControllerStyle.alert
    )
    alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel) { alert in
        if AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo).count > 0 {
            AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { granted in
                DispatchQueue.main.async() {
                    self.checkCamera() } }
        }
        }
    )
    present(alert, animated: true, completion: nil)
}

感谢上面的jamix作为使用dispatch_async的技巧-使显示新设置的摄像头功能的响应变得更快。

很抱歉混合了尾随的闭包..想尝试一下。


我被挑剔/好奇在这里,但你为什么要设置style: .DefaultCancel按钮,并style: .Cancel其他按钮?只是一个错误还是您有目的地这样做?
SaltyNuts

想想我只是想一个比另一个更突出,仅此而已。像粗体还是普通字体。
DogCoffee 2015年

@DogCoffee对于最初访问相机的权限提示,我有些困惑。这不是开发人员无法模仿的iOS内置功能吗?我们只能检查它是否之前被拒绝过,然后提示更新设置?
user2363025 2015年

我前阵子做了这个,该应用需要我的QR阅读器使用相机。iOS确实询问是否可以使用相机。我只是想让用户知道为什么。在大多数情况下,事情突然出现时,我通常会首先拒绝。这只是我的发言方式-请接受。
DogCoffee,2015年

@DogCoffee因此,我实际上不需要为首次访问权限提示创建函数,我可以让iOS在后台执行此操作,并且我只需要照顾他们过去是否拒绝过权限?
user2363025

16

这些答案似乎都无法同时检查麦克风和摄像头的权限。我们的代码将检查授予摄像机权限但拒绝麦克风访问的情况。

由于我们是Swift的新手,因此不太可能嵌套嵌套的闭包和if语句是最佳的。请分享改进代码的建议!但是至少到目前为止,它在测试中仍然有效。

    AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (videoGranted: Bool) -> Void in
        if (videoGranted) {
            AVCaptureDevice.requestAccessForMediaType(AVMediaTypeAudio, completionHandler: { (audioGranted: Bool) -> Void in
                if (audioGranted) {
                    dispatch_async(dispatch_get_main_queue()) {
                        // Both video & audio granted
                    }
                } else {
                    // Rejected audio
                }
            })
        } else {
            // Rejected video
        }
    })

1
仅回答同时解决视频和音频权限的问题。旁注,对我来说,这太疯狂了,您不能要求将两者结合使用,谢谢苹果。
lostintranslation

这是正确的答案。对于视频录制,这很关键,否则在初始化会话时,系统将自行启动音频权限。这样,您的应用程序就不会知道它了,它实质上是为用户“铺平了”体验。我注意到很多项目只是忽略了这一点,男孩哦,男孩确实会产生大量的客户支持票:)
Ryan Romanchuk

8
  • Swift 3.0解决方案

    导入AVFoundation

注意:在Info.plist上添加Privacy-Camera Use Description键

// MARK:相机处理

        func callCamera(){
            let myPickerController = UIImagePickerController()
            myPickerController.delegate = self;
            myPickerController.sourceType = UIImagePickerControllerSourceType.camera

            self.present(myPickerController, animated: true, completion: nil)
            NSLog("Camera");
        }
        func checkCamera() {
            let authStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
            switch authStatus {
            case .authorized: callCamera() // Do your stuff here i.e. callCameraMethod()
            case .denied: alertToEncourageCameraAccessInitially()
            case .notDetermined: alertPromptToAllowCameraAccessViaSetting()
            default: alertToEncourageCameraAccessInitially()
            }
        }

        func alertToEncourageCameraAccessInitially() {
            let alert = UIAlertController(
                title: "IMPORTANT",
                message: "Camera access required for capturing photos!",
                preferredStyle: UIAlertControllerStyle.alert
            )
            alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
            alert.addAction(UIAlertAction(title: "Allow Camera", style: .cancel, handler: { (alert) -> Void in
                UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!)
            }))
            present(alert, animated: true, completion: nil)
        }

        func alertPromptToAllowCameraAccessViaSetting() {

            let alert = UIAlertController(
                title: "IMPORTANT",
                message: "Camera access required for capturing photos!",
                preferredStyle: UIAlertControllerStyle.alert
            )
            alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel) { alert in
                if AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo).count > 0 {
                    AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { granted in
                        DispatchQueue.main.async() {
                            self.checkCamera() } }
                }
                }
            )
            present(alert, animated: true, completion: nil)
        }

您已切换方法;-)“通过设置”启动“烫发”对话框,第二个启动设置对话框:-)
matrejek

5

对于Swift 3,您可以将其添加到viewWillAppear第一个视图控制器的方法中:

首先导入AVFoundation框架

import AVFoundation

然后:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let authorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)

    switch authorizationStatus {
    case .notDetermined:
        AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { granted in
            if granted {
                print("access granted")
            }
            else {
                print("access denied")
            }
        }
    case .authorized:
        print("Access authorized")
    case .denied, .restricted:
        print("restricted")

    }
}

不要忘记Privacy - Camera Usage Description在您的钥匙上添加钥匙Info.plist


4

对我来说,这适用于iOS7和iOS8:

    ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];

    switch (status) {
        case ALAuthorizationStatusAuthorized:
            break;

        case ALAuthorizationStatusRestricted:
        case ALAuthorizationStatusDenied:
            break;

        case ALAuthorizationStatusNotDetermined:
            break;
    }

3
它像一种魅力。不要忘了进口:#import <AssetsLibrary/AssetsLibrary.h>
乔纳森·F。

由于已弃用ALAssetsLibrary,因此在IOS 9中不再可用。
Supertecnoboff 2015年

3

我对应用程序委托进行访问检查。

import UIKit
import AVFoundation
import Photos

        func applicationDidBecomeActive(application: UIApplication) {
            cameraAllowsAccessToApplicationCheck()
            internetAvailabilityOnApplicationCheck()
            photoLibraryAvailabilityCheck()
        }

    //MARK:- CAMERA ACCESS CHECK
        func cameraAllowsAccessToApplicationCheck()
        {
            let authorizationStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)
            switch authorizationStatus {
            case .NotDetermined:
                // permission dialog not yet presented, request authorization
                AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo,
                    completionHandler: { (granted:Bool) -> Void in
                        if granted {
                            print("access granted")
                        }
                        else {
                            print("access denied")
                        }
                })
            case .Authorized:
                print("Access authorized")
            case .Denied, .Restricted:
            alertToEncourageCameraAccessWhenApplicationStarts()
            default:
                print("DO NOTHING")
            }
        }
        //MARK:- PHOTO LIBRARY ACCESS CHECK
        func photoLibraryAvailabilityCheck()
        {
            if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.Authorized
            {

            }
            else
            {
                var cameraUnavailableAlertController = UIAlertController (title: "Photo Library Unavailable", message: "Please check to see if device settings doesn't allow photo library access", preferredStyle: .Alert)

                var settingsAction = UIAlertAction(title: "Settings", style: .Destructive) { (_) -> Void in
                    let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
                    if let url = settingsUrl {
                        UIApplication.sharedApplication().openURL(url)
                    }
                }
                var cancelAction = UIAlertAction(title: "Okay", style: .Default, handler: nil)
                cameraUnavailableAlertController .addAction(settingsAction)
                cameraUnavailableAlertController .addAction(cancelAction)
                self.window?.rootViewController!.presentViewController(cameraUnavailableAlertController , animated: true, completion: nil)
            }
        }
        func internetAvailabilityOnApplicationCheck()
        {
            //MARK:- INTERNET AVAILABLITY
            if InternetReachability.isConnectedToNetwork() {

            }
            else
            {
                dispatch_async(dispatch_get_main_queue(), {

                    //INTERNET NOT AVAILABLE ALERT
                    var internetUnavailableAlertController = UIAlertController (title: "Network Unavailable", message: "Please check your internet connection settings and turn on Network Connection", preferredStyle: .Alert)

                    var settingsAction = UIAlertAction(title: "Settings", style: .Destructive) { (_) -> Void in
                        let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
                        if let url = settingsUrl {
                            UIApplication.sharedApplication().openURL(url)
                        }
                    }
                    var cancelAction = UIAlertAction(title: "Okay", style: .Default, handler: nil)
                    internetUnavailableAlertController .addAction(settingsAction)
                    internetUnavailableAlertController .addAction(cancelAction)
                    self.window?.rootViewController!.presentViewController(internetUnavailableAlertController , animated: true, completion: nil)
                })
            }
        }

*


2

对我来说,问题是由于最近的构建配置更改,Bundle name并且Bundle Display Name没有在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.