Reputation: 14835
I am using this code, but unfortunately it doesn't work.
After a user has denied camera access, I want to ask them for permission to use the camera again the next time they try to load it (in this case it's a barcode scanner using the camera view). I always get AVAuthorizationStatusDenied
and then granted
always automatically returns NO
even though I ask for it again in code.
Many of my users are e-mailing me saying "my screen is black when I try to barcode scan" and it's because they have denied camera access for some reason. I want to be able to prompt them again because most likely the denial was a mistake.
Is there a possible way to do this?
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.");
}
Upvotes: 64
Views: 53722
Reputation: 14835
After some research it looks like you can't do what I'd like. Here is the alternative that I coded to pop a dialog and open the Settings app automatically if on iOS 8+.
Some notes:
NSCameraUsageDescription
key in your Info.plist to be able ask for camera access, otherwise your app will crash at runtime.Swift 5.2:
At the top of your view controller:
import AVFoundation
Before opening the camera view:
@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()
}
}
Denial alert with completion block:
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:
At the top of your view controller:
#import <AVFoundation/AVFoundation.h>
Before opening the camera view:
- (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];
}
}
Denial alert:
- (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];
}
Delegate call for the UIAlertView:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (alertView.tag == 3491832)
{
BOOL canOpenSettings = (&UIApplicationOpenSettingsURLString != NULL);
if (canOpenSettings)
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}
}
Upvotes: 97
Reputation: 25938
Full code of Camera access and photo library access
import AVFoundation
To handle camera action use the below code: Method calling
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()
}
Method to handle camera access functionality
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
}
Upvotes: 1
Reputation: 781
For Swift 3.0
This will lead the user to settings for changing the permission.
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
}
Upvotes: 3
Reputation: 16290
Once they have denied camera access, the user can authorize camera use for your app in Settings. By design, you can't override this in your own code.
You can detect this case with the following sample code and then explain to the user how to fix it: 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");
}
Upvotes: 11