Я разрабатываю очень простое видео-приложение. Я использую официальный элемент управления: UIImagePickerController.
Вот в чем проблема. При первом представлении UIImagePickerController iOS запросит разрешение. Пользователь может щелкнуть да или нет. Если пользователь нажимает кнопку «Нет», элемент управления не закрывается. Вместо этого, если пользователь продолжает нажимать кнопку запуска, таймеры продолжаются, пока экран всегда черный, и пользователь не может остановить таймеры или вернуться. Единственное, что может сделать пользователь, - это убить приложение. В следующий раз, когда будет представлен UIImagePickerController, это все еще будет черный экран, и пользователь не сможет вернуться, нажав кнопку «Пуск».
Мне было интересно, не ошибка ли это. Есть ли способ определить разрешение камеры, чтобы мы могли решить, отображать UIImagePickerController или нет?
UIImageViewController
отмечен как добавленный в iOS 2.0, и документы никогда не аннотируются, чтобы отразить, что AVAuthorizationStatus следует использовать, но живет в другой структуре.Ответы:
Проверьте
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 }
источник
#import <AVFoundation/AVFoundation.h>
или аналогичныйBundle ID
приложение каждый раз, когда я хочу это проверить. Боль в заднице, но хоть что-то. Просто не забудьте вернуть идентификатор, когда закончите ;-)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 убивает приложение, если оно работает, пока вы меняете разрешения камеры в настройках?
С форума разработчиков Apple:
источник
Быстрое решение
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 })
источник
В дополнение к ответу @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 } } } } }
источник
Сначала укажите ключ NSCameraUsageDescription в Info.plist. Затем проверьте AVAuthorizationStatus, если авторизован, затем представьте UIImagePickerController. Это будет работать.
источник
Swift: использование AVFoundation
@IBAction func cameraButtonClicked (отправитель: 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) }
источник