Detecta el permiso de la cámara en iOS

Estoy desarrollando una aplicación de video muy simple. Uso el control oficial: UIImagePickerController.

Aquí está el problema Al presentar el UIImagePickerController por primera vez, iOS solicitará el permiso. El usuario puede hacer clic en sí o no. Si el usuario hace clic en no, el control no se descarta. En cambio, si el usuario sigue haciendo clic en el botón de inicio, los temporizadores se activan mientras la pantalla siempre está en negro, y el usuario no puede detener los temporizadores o regresar. Lo único que puede hacer el usuario es matar la aplicación. La próxima vez que se presente el UIImagePickerController, sigue siendo una pantalla negra y el usuario no puede volver atrás si hace clic en iniciar.

Me preguntaba si es un error. ¿Hay alguna manera de que podamos detectar el permiso de la cámara para que podamos decidir mostrar el UIImagePickerController o no?

Verifique el estado de AVAuthorizationStatus y maneje las cajas de manera adecuada.

 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 } 

Desde iOS 10, debes especificar la clave NSCameraUsageDescription en tu Info.plist para poder solicitar acceso a la cámara, de lo contrario, tu aplicación se bloqueará en el tiempo de ejecución. Ver las API que requieren descripciones de uso .


Asegurate que:

 import AVFoundation 

El siguiente código Swift comprueba todos los posibles estados de permiso:

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

Swift 2.2

 let cameraMediaType = AVMediaTypeVideo let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatusForMediaType(cameraMediaType) switch cameraAuthorizationStatus { case .Denied: break case .Authorized: break case .Restricted: break case .NotDetermined: // Prompting user for the permission to use the camera. AVCaptureDevice.requestAccessForMediaType(cameraMediaType) { granted in if granted { print("Granted access to \(cameraMediaType)") } else { print("Denied access to \(cameraMediaType)") } } } 

Como nota al margen interesante, ¿sabías que iOS mata la aplicación si se está ejecutando mientras cambias los permisos de la cámara en Configuración?

Desde el foro de desarrolladores de Apple:

El sistema realmente mata su aplicación si el usuario cambia el acceso de su aplicación a la cámara en Configuración. Lo mismo se aplica a cualquier clase de datos protegida en la sección Configuración → Privacidad.

 extension AVCaptureDevice { enum AuthorizationStatus { case justDenied case alreadyDenied case restricted case justAuthorized case alreadyAuthorized } class func authorizeVideo(completion: ((AuthorizationStatus) -> Void)?) { AVCaptureDevice.authorize(mediaType: AVMediaTypeVideo, completion: completion) } class func authorizeAudio(completion: ((AuthorizationStatus) -> Void)?) { AVCaptureDevice.authorize(mediaType: AVMediaTypeAudio, completion: completion) } private class func authorize(mediaType: String, completion: ((AuthorizationStatus) -> Void)?) { let status = AVCaptureDevice.authorizationStatus(forMediaType: mediaType) switch status { case .authorized: completion?(.alreadyAuthorized) case .denied: completion?(.alreadyDenied) case .restricted: completion?(.restricted) case .notDetermined: AVCaptureDevice.requestAccess(forMediaType: mediaType, completionHandler: { (granted) in if(granted) { completion?(.justAuthorized) } else { completion?(.justDenied) } }) } } } 

Y luego para usarlo lo haces

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

Como una adición a la respuesta de @Raptor, se debe mencionar lo siguiente. Puede recibir el siguiente error comenzando con 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. 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.

Para solucionar esto, asegúrese de manejar los resultados del hilo principal de la siguiente manera (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 } } } } } 

Especifique primero la clave NSCameraUsageDescription en Info.plist. Luego, compruebe AVAuthorizationStatus si está autorizado y luego presente el UIImagePickerController. Funcionará.

Swift: Usando AVFoundation

  1. Agregue AVFoundation a Target -> Build Fases -> Link Binary con Bibliotecas.
  2. importar AVFoundation en ViewController.
  3. En Info.plist, agregue lo siguiente:

enter image description here

  1. En el controlador de vista:

@IBAction func cameraButtonClicked (remitente: 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) }