iOS上,用户拒绝了相机权限后,是否有一种方法可以再次请求访问相机?

64

我正在使用这段代码,但不幸的是它不起作用。

在用户拒绝相机访问后,我想要在下一次尝试加载时再次请求他们允许使用相机(在这种情况下是使用相机视图的条形码扫描器)。无论我如何在代码中再次请求权限,我总是得到AVAuthorizationStatusDenied,并且granted始终自动返回NO

我的许多用户给我发电子邮件说:“当我尝试进行条形码扫描时,我的屏幕变黑了”,这是因为他们出于某种原因拒绝了相机访问。我希望能够再次提示他们,因为很可能这种拒绝是一个错误。

有可能做到这一点吗?

    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if(authStatus == AVAuthorizationStatusAuthorized)
    {
        NSLog(@"%@", @"You have camera access");
    }
    else if(authStatus == AVAuthorizationStatusDenied)
    {
        NSLog(@"%@", @"Denied camera access");

        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            if(granted){
                NSLog(@"Granted access to %@", AVMediaTypeVideo);
            } else {
                NSLog(@"Not granted access to %@", AVMediaTypeVideo);
            }
        }];
    }
    else if(authStatus == AVAuthorizationStatusRestricted)
    {
        NSLog(@"%@", @"Restricted, normally won't happen");
    }
    else if(authStatus == AVAuthorizationStatusNotDetermined)
    {
        NSLog(@"%@", @"Camera access not determined. Ask for permission.");

        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            if(granted){
                NSLog(@"Granted access to %@", AVMediaTypeVideo);
            } else {
                NSLog(@"Not granted access to %@", AVMediaTypeVideo);
            }
        }];
    }
    else
    {
        NSLog(@"%@", @"Camera access unknown error.");
    }

4
很遗憾没有再次询问的办法。您需要弹出一个UIAlertView并让用户知道在设置中启用它。为了帮助减少用户意外点击拒绝的情况,一种选择是在询问之前创建一个闪屏,并警告用户如果不允许,则无法正确使用该应用程序。 - TyloBedo
4个回答

97
经过一些研究,看起来你不能做我想要的事情。以下是我编写的替代方案,可弹出对话框并自动打开设置应用程序(如果在iOS 8+上)。
一些注意事项:
- 自iOS 10以来,您需要在Info.plist中指定NSCameraUsageDescription键才能请求相机访问权限,否则您的应用程序将在运行时崩溃。 - 一旦用户更改了您的应用程序的任何权限,它将终止您的应用程序。请适当处理并保存用户点击“Go”按钮之前所需的任何数据。 - 在iOS 8和11之间的某个时刻,苹果不再要求用户触摸设置应用程序中的隐私单元格即可进入并更改相机设置。根据用户使用的iOS版本更改您在设置应用程序中指示用户执行的操作说明可能更好。如果有人想留言告诉我们确切的iOS版本变化时间,那就太棒了。 - 我们最后编辑这篇答案时,下面的代码在iOS 14.2上可以工作。
Swift 5.2:
在您的视图控制器顶部:
import AVFoundation

在打开相机视图之前:

@IBAction func goToCamera()
{
    let status = AVCaptureDevice.authorizationStatus(for: .video)
    switch (status)
    {
    case .authorized:
        self.popCamera()

    case .notDetermined:
        AVCaptureDevice.requestAccess(for: .video) { (granted) in
            if (granted)
            {
                self.popCamera()
            }
            else
            {
                self.camDenied()
            }
        }

    case .denied:
        self.camDenied()

    case .restricted:
        let alert = UIAlertController(title: "Restricted",
                                      message: "You've been restricted from using the camera on this device. Without camera access this feature won't work. Please contact the device owner so they can give you access.",
                                      preferredStyle: .alert)

        let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
        alert.addAction(okAction)
        self.present(alert, animated: true, completion: nil)
    @unknown default:
        fatalError()
    }
}

带有完成块的拒绝警报:

func camDenied()
{
    DispatchQueue.main.async
    {
        var alertText = "It looks like your privacy settings are preventing us from accessing your camera to do barcode scanning. You can fix this by doing the following:\n\n1. Close this app.\n\n2. Open the Settings app.\n\n3. Scroll to the bottom and select this app in the list.\n\n4. Turn the Camera on.\n\n5. Open this app and try again."

        var alertButton = "OK"
        var goAction = UIAlertAction(title: alertButton, style: .default, handler: nil)

        if UIApplication.shared.canOpenURL(URL(string: UIApplication.openSettingsURLString)!)
        {
            alertText = "It looks like your privacy settings are preventing us from accessing your camera to do barcode scanning. You can fix this by doing the following:\n\n1. Touch the Go button below to open the Settings app.\n\n2. Turn the Camera on.\n\n3. Open this app and try again."

            alertButton = "Go"

            goAction = UIAlertAction(title: alertButton, style: .default, handler: {(alert: UIAlertAction!) -> Void in
                UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
            })
        }

        let alert = UIAlertController(title: "Error", message: alertText, preferredStyle: .alert)
        alert.addAction(goAction)
        self.present(alert, animated: true, completion: nil)
    }
}

Objective-C:

在您的视图控制器顶部:

#import <AVFoundation/AVFoundation.h>

在打开相机视图之前:

- (IBAction)goToCamera
{
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if(authStatus == AVAuthorizationStatusAuthorized)
    {
        [self popCamera];
    }
    else if(authStatus == AVAuthorizationStatusNotDetermined)
    {
        NSLog(@"%@", @"Camera access not determined. Ask for permission.");
        
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted)
        {
            if(granted)
            {
                NSLog(@"Granted access to %@", AVMediaTypeVideo);
                [self popCamera];
            }
            else
            {
                NSLog(@"Not granted access to %@", AVMediaTypeVideo);
                [self camDenied];
            }
        }];
    }
    else if (authStatus == AVAuthorizationStatusRestricted)
    {
        // My own Helper class is used here to pop a dialog in one simple line.
        [Helper popAlertMessageWithTitle:@"Error" alertText:@"You've been restricted from using the camera on this device. Without camera access this feature won't work. Please contact the device owner so they can give you access."];
    }
    else
    {
        [self camDenied];
    }
}

拒绝警报:

- (void)camDenied
{
    NSLog(@"%@", @"Denied camera access");
    
    NSString *alertText;
    NSString *alertButton;
    
    BOOL canOpenSettings = (&UIApplicationOpenSettingsURLString != NULL);
    if (canOpenSettings)
    {
        alertText = @"It looks like your privacy settings are preventing us from accessing your camera to do barcode scanning. You can fix this by doing the following:\n\n1. Touch the Go button below to open the Settings app.\n\n2. Turn the Camera on.\n\n3. Open this app and try again.";
        
        alertButton = @"Go";
    }
    else
    {
        alertText = @"It looks like your privacy settings are preventing us from accessing your camera to do barcode scanning. You can fix this by doing the following:\n\n1. Close this app.\n\n2. Open the Settings app.\n\n3. Scroll to the bottom and select this app in the list.\n\n4. Turn the Camera on.\n\n5. Open this app and try again.";
        
        alertButton = @"OK";
    }
    
    UIAlertView *alert = [[UIAlertView alloc]
                          initWithTitle:@"Error"
                          message:alertText
                          delegate:self
                          cancelButtonTitle:alertButton
                          otherButtonTitles:nil];
    alert.tag = 3491832;
    [alert show];
}

UIAlertView的代理调用:

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (alertView.tag == 3491832)
    {
        BOOL canOpenSettings = (&UIApplicationOpenSettingsURLString != NULL);
        if (canOpenSettings)
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
    }
}

1
你忘记处理“受限制”状态了。这与如何处理“拒绝访问”是非常不同的。 - rmaddy
你的启动设置代码不正确。它会在设置应用中启动你自己的应用程序设置页面,而不是通用设置页面。 - rmaddy
3
@maddy - “受限制”和“限制”有什么不同吗?是的,我希望它可以跳转到我的应用程序的设置页面……那里你可以更改隐私设置以允许访问相机。 - Ethan Allen
еҘҪзҡ„пјҢжҲ‘е·Із»Ҹжӣҙж–°дәҶд»Јз Ғд»ҘиҖғиҷ‘AVAuthorizationStatusRestrictedгҖӮ - Ethan Allen
2
@EthanAllen 我对设置页面的启动时间做出了更正。这是iOS 8的一个新功能,现在所有应用程序都会出现在设置应用程序中,而不仅仅是具有设置包的应用程序。没有设置包的应用程序显示隐私设置。 - rmaddy
显示剩余10条评论

11

如果用户拒绝了相机访问权限,您可以通过“设置”授权您的应用程序使用相机。根据设计,您不能在自己的代码中覆盖此设置。

您可以使用以下示例代码检测此情况,然后向用户解释如何解决:iOS 7 UIImagePickerController Camera No Image

NSString *mediaType = AVMediaTypeVideo; // Or AVMediaTypeAudio

AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];

// The user has explicitly denied permission for media capture.
else if(authStatus == AVAuthorizationStatusDenied){
    NSLog(@"Denied");
}

3

适用于Swift 3.0

这将把用户带到更改权限的设置页面。

func checkCameraAuthorise() -> Bool {
    let status = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
    if status == .restricted || status == .denied {
        let dialog = ZAlertView(title: "", message: "Please allow access to the camera in the device's Settings -> Privacy -> Camera", isOkButtonLeft: false, okButtonText: "OK", cancelButtonText: "Cancel", okButtonHandler:
            { _ -> Void in UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!)}, cancelButtonHandler: { alertView in alertView.dismissAlertView() })
        dialog.show()
        return false
    }
    return true
}

1

相机访问和照片库访问的完整代码

import AVFoundation

使用以下代码处理相机操作: 方法调用

func openCameraOrLibrary(){
    let imagePicker = UIImagePickerController()
    let alertController : UIAlertController = UIAlertController(title: "Select Camera or Photo Library".localized, message: "", preferredStyle: .actionSheet)
    let cameraAction : UIAlertAction = UIAlertAction(title: "Camera".localized, style: .default, handler: {(cameraAction) in

        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) == true {
            if self.isCamAccessDenied() == false { **//Calling cam access method here**
                imagePicker.sourceType = .camera
                imagePicker.delegate = self
                self.present(imagePicker, animated: true, completion: nil)
            }

        }else{
            self.present(self.showAlert(Title: "", Message: "Camera is not available on this Device or accesibility has been revoked!".localized), animated: true, completion: nil)
            self.showTabbar()

        }

    })

    let libraryAction : UIAlertAction = UIAlertAction(title: "Photo Library", style: .default, handler: {(libraryAction) in

        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary) == true {

            imagePicker.sourceType = .photoLibrary
            imagePicker.delegate = self
            self.present(imagePicker, animated: true, completion: nil)

        }else{
            self.showTabbar()
            self.present(self.showAlert(Title: "", Message: "Photo Library is not available on this Device or accesibility has been revoked!".localized), animated: true, completion: nil)
        }
    })

    let cancelAction : UIAlertAction = UIAlertAction(title: "Cancel".localized, style: .cancel , handler: {(cancelActn) in
        self.showTabbar()
    })

    alertController.addAction(cameraAction)

    alertController.addAction(libraryAction)

    alertController.addAction(cancelAction)

    alertController.popoverPresentationController?.sourceView = view
    alertController.popoverPresentationController?.sourceRect = view.frame

    self.present(alertController, animated: true, completion: nil)
    self.hideTabbar()

}

处理相机访问功能的方法。
func isCamAccessDenied()-> Bool
{
    let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
    if status == .restricted || status == .denied {
    DispatchQueue.main.async
        {
            var alertText = "It looks like your privacy settings are preventing us from accessing your camera to do barcode scanning. You can fix this by doing the following:\n\n1. Close this app.\n\n2. Open the Settings app.\n\n3. Scroll to the bottom and select this app in the list.\n\n4. Turn the Camera on.\n\n5. Open this app and try again."

            var alertButton = "OK"
            var goAction = UIAlertAction(title: alertButton, style: .default, handler: nil)

            if UIApplication.shared.canOpenURL(URL(string: UIApplicationOpenSettingsURLString)!)
            {
                alertText = "It looks like your privacy settings are preventing us from accessing your camera to do barcode scanning. You can fix this by doing the following:\n\n1. Touch the Go button below to open the Settings app.\n\n2. Turn the Camera on.\n\n3. Open this app and try again."

                alertButton = "OK"

                goAction = UIAlertAction(title: alertButton, style: .default, handler: {(alert: UIAlertAction!) -> Void in
                    UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)!, options: [:], completionHandler: nil)
                })
            }

            let alert = UIAlertController(title: "Error", message: alertText, preferredStyle: .alert)
            alert.addAction(goAction)
            self.present(alert, animated: true, completion: nil)
        }
        return true
    }
    return false
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接