Обнаружить разрешение камеры в iOS
Я разрабатываю очень простое видео приложение. Я использую официальный контроль: UIImagePickerController.
Вот проблема. При представлении UIImagePickerController в первый раз, iOS запросит разрешение. Пользователь может нажать "Да" или "Нет". Если пользователь не нажимает кнопку "Нет", элемент управления не отменяется. Вместо этого, если пользователь продолжает нажимать кнопку запуска, таймеры продолжаются, когда экран всегда черный, и пользователь не может остановить таймеры или вернуться. Единственное, что пользователь может сделать, это убить приложение. В следующий раз, когда представлен UIImagePickerController, он по-прежнему является черным экраном, и пользователь не может вернуться, если нажать кнопку "Пуск".
Мне было интересно, если это ошибка. Можно ли каким-либо образом определить разрешение камеры, чтобы мы могли решить показать UIImagePickerController или нет?
Ответы
Ответ 1
Проверьте 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
}
Ответ 2
Начиная с iOS 10, вам нужно указать ключ NSCameraUsageDescription
в вашем Info.plist, чтобы иметь возможность запрашивать доступ к камере, иначе ваше приложение будет зависать во время выполнения. См. API, требующие описания использования.
Убедись в:
import AVFoundation
Приведенный ниже код Swift проверяет все возможные состояния разрешений:
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)")
}
}
}
Свифт 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)")
}
}
}
В качестве интересного примечания: знаете ли вы, что iOS убивает приложение, если оно работает, в то время как вы меняете разрешения камеры в настройках?
С форума разработчиков Apple:
Система фактически убивает ваше приложение, если пользователь переключает доступ вашего приложения к камере в настройках. То же самое относится к любому защищенному классу данных в разделе Настройки → Конфиденциальность.
Ответ 3
В качестве дополнения к ответу от @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
}
}
}
}
}
Ответ 4
Быстрое Решение
extension AVCaptureDevice {
enum AuthorizationStatus {
case justDenied
case alreadyDenied
case restricted
case justAuthorized
case alreadyAuthorized
}
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)
}
}
})
}
}
}
И затем, чтобы использовать его, вы делаете
AVCaptureDevice.authorizeVideo(completion: { (status) in
//Your work here
})
Ответ 5
Сначала укажите ключ NSCameraUsageDescription в Info.plist. Затем проверьте AVAuthorizationStatus, если авторизован, затем представьте UIImagePickerController. Это будет работать.
Ответ 6
Swift: использование AVFoundation
- Добавить AVFoundation to Target → Сборка фаз → Связывание двоичных файлов с библиотеками.
- импортировать AVFoundation на ViewController.
- В Info.plist добавьте следующее:
![введите описание изображения здесь]()
- Контроллер просмотра:
@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)
}