Виявлення дозволу камери в iOS


143

Я розробляю дуже простий додаток для відео. Я використовую офіційний контроль: UIImagePickerController.

Ось проблема. Під час першого представлення UIImagePickerController iOS запитає дозволу. Користувач може натиснути так чи ні. Якщо користувач натискає "ні", контроль не відхиляється. Натомість, якщо користувач продовжує натискати кнопку "Пуск", таймери вмикаються, поки екран завжди чорний, і користувач не може зупинити таймери або повернутися назад. Єдине, що може зробити користувач - це вбити додаток. Наступного разу, коли UIImagePickerController буде представлений, це все ще чорний екран, і користувач не може повернутися назад, натиснувши кнопку "Пуск".

Мені було цікаво, чи це помилка. Чи є спосіб виявити дозвіл камери, щоб ми могли вирішити показати UIImagePickerController чи ні?


Re: це помилка? IMHO, я думаю, що так, тому що, здається, трапляється те, що VC відображає дані з обладнання, але ОС в основному посилає мертве повітря. Як iOS потрапив сюди, ймовірно, є побічним ефектом еволюції сімейства продуктів. UIImageViewControllerзазначається, що додається в iOS 2.0, і документи ніколи не коментуються, що відображають, що AVAuthorizationStatus слід використовувати, але він живе в інших рамках.
benc

Відповіді:


229

Перевірте 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
}

19
також вимагає: #import <AVFoundation/AVFoundation.h>або подібного
toblerpwn

9
Можливо корисна порада - якщо ви тестуєте код, який використовує це, ви не можете просто видалити свою програму з тестового пристрою, а потім повторно встановити. Це не призведе до того, що iOS перезапустить запит користувачеві! Що для мене працює, але це змінювати Bundle IDдодаток щоразу, коли я хочу це перевірити. Біль в області шишки, але щось, принаймні. Просто пам’ятайте, щоб повернути ідентифікатор, коли ви закінчите ;-)
Бенджон

25
@Benjohn: зміна ідентифікатора групи не потрібна. Ви можете перейти в Налаштування> Загальне> Скинути і знайти налаштування, яке скине всі підказки дозволу на пристрої. Зрозуміло, це також дратує, оскільки це впливає і на всі інші програми на вашому пристрої. Якби тільки Apple могла додати для цього елементи керування для додатків у розділі «Розвиток» Settings.app ...
KennyDeriemaeker

3
@KennyDeriemaeker :-) Apple може відповісти, що ми повинні використовувати спеціальні пристрої для тестування! Для мене побічні ефекти від скидання мого звичайного телефону були б дуже вдалі. Зміна пачки Id була досить безболісною альтернативою. Я згадав змінити його ще до подання :-)
Бенджон

8
Просто переконайтеся, що ви не зробите повне скидання! Достатньо просто скинути налаштування конфіденційності та місцеположення (iOS 8).
Canucklesandwich

81

Швидкий 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:

Система фактично вбиває ваш додаток, якщо користувач перемикає доступ вашої програми на камеру в Налаштуваннях. Те саме стосується будь-якого захищеного класу даних у розділі Налаштування → Конфіденційність.


А як щодо авторизації камери та фотогалереї
Хаджар ЕЛКОУМІХІ

4

Швидке рішення

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

А як щодо авторизації камери та фотогалереї ??
Хаджар ЕЛКОУМІХІ

2

Як додаток до відповіді від @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
                }
            }
        }
    }
}

У разі відхилення метод requestAccess не працюватиме. Вам доведеться вручну показати сповіщення, щоб попросити користувача перейти до налаштувань та надати дозволи.
Абдулла Умер

0

Спершу вкажіть ключ NSCameraUsageDescription у Info.plist. Потім перевірте AVAuthorizationStatus, якщо Авторизовано, тоді представіть UIImagePickerController. Це спрацює.


-4

Швидкий: Використання AVFoundation

  1. Додайте AVFoundation до цілі -> Фази збірки -> Пов’язати бінарне з бібліотеками.
  2. імпортувати AVFoundation на ViewController.
  3. У Info.plist додайте наступне:

введіть тут опис зображення

  1. Контролер перегляду:

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

Що з записами Info.plist? Джерело?
Білл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.