Erkennen Sie die Berechtigung der Kamera in iOS

143

Ich entwickle eine sehr einfache Video-App. Ich benutze das offizielle Steuerelement: UIImagePickerController.

Hier ist das Problem. Bei der erstmaligen Präsentation des UIImagePickerController fragt iOS nach der Erlaubnis. Der Benutzer kann auf Ja oder Nein klicken. Wenn der Benutzer auf Nein klickt, wird das Steuerelement nicht geschlossen. Wenn der Benutzer weiterhin auf die Startschaltfläche klickt, werden die Timer fortgesetzt, während der Bildschirm immer schwarz ist, und der Benutzer kann die Timer nicht stoppen oder zurückgehen. Der Benutzer kann nur die App beenden. Wenn der UIImagePickerController das nächste Mal angezeigt wird, ist er immer noch schwarz und der Benutzer kann nicht zurückkehren, wenn er auf Start klickt.

Ich habe mich gefragt, ob es ein Fehler ist. Gibt es eine Möglichkeit, die Berechtigung der Kamera zu erkennen, um zu entscheiden, ob der UIImagePickerController angezeigt werden soll oder nicht?

user418751
quelle
Re: ist es ein Fehler? IMHO, ich denke schon, denn was zu passieren scheint, ist, dass der VC die Daten von der Hardware anzeigt, aber das Betriebssystem im Grunde tote Luft sendet. Wie iOS hierher kam, ist wahrscheinlich ein Nebeneffekt der Entwicklung der Produktfamilie. UIImageViewControllerwird in iOS 2.0 hinzugefügt, und die Dokumente wurden nie mit Anmerkungen versehen, um anzuzeigen, dass der AVAuthorizationStatus verwendet werden sollte, sondern in einem anderen Framework ausgeführt wird.
Benc

Antworten:

229

Überprüfen Sie AVAuthorizationStatusdie Fälle und behandeln Sie sie ordnungsgemäß.

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
}
Raubvogel
quelle
19
erfordert auch: #import <AVFoundation/AVFoundation.h>oder ähnliches
toblerpwn
9
Ein möglicherweise nützlicher Tipp: Wenn Sie Code testen, der dies verwendet, können Sie Ihre App nicht einfach vom Testgerät löschen und dann erneut installieren. Dies führt nicht dazu, dass iOS die Anfrage erneut an den Benutzer sendet! Was für mich jedoch funktioniert hat, ist, Bundle IDdie App jedes Mal zu ändern, wenn ich dies testen möchte. Ein Schmerz im Hintern, aber zumindest etwas.
Denken
25
@Benjohn: Das Ändern der Bundle-ID ist nicht erforderlich. Gehen Sie zu Einstellungen> Allgemein> Zurücksetzen und suchen Sie eine Einstellung, mit der alle Berechtigungsaufforderungen auf dem Gerät zurückgesetzt werden. Zugegeben, das ist auch ärgerlich, da es auch alle anderen Apps auf Ihrem Gerät betrifft. Wenn nur Apple Apps-spezifische Steuerelemente dafür im Abschnitt "Entwicklung" von Settings.app hinzufügen könnte ...
KennyDeriemaeker
3
@KennyDeriemaeker :-) Apple könnte antworten, dass wir dedizierte Geräte zum Testen verwenden sollen! Für mich wären die Nebenwirkungen des Zurücksetzens meines normalen Telefons ziemlich blöd gewesen. Das Ändern der Bundle-ID war eine ziemlich schmerzlose Alternative. Ich erinnerte mich, es auch vor der Einreichung wieder zu ändern :-)
Benjohn
8
Stellen Sie nur sicher, dass Sie keinen vollständigen Reset durchführen! Es reicht aus, nur die Einstellungen für Datenschutz und Standort (iOS 8) zurückzusetzen.
Canucklesandwich
81

Swift 4 und neuer

Stellen Sie sicher, dass:

import AVFoundation

Der folgende Code prüft auf alle möglichen Berechtigungszustände:

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

Seit iOS 10 müssen Sie NSCameraUsageDescriptionin Ihrer Info.plist einen Schlüssel angeben, um nach dem Zugriff auf die Kamera fragen zu können. Andernfalls stürzt Ihre App zur Laufzeit ab. Siehe APIs, für die Verwendungsbeschreibungen erforderlich sind .


Wussten Sie als interessante Randnotiz, dass iOS die App beendet, wenn sie ausgeführt wird, während Sie die Kameraberechtigungen in den Einstellungen ändern?

Aus dem Apple Developer Forum:

Das System beendet Ihre App tatsächlich, wenn der Benutzer den Zugriff Ihrer App auf die Kamera in den Einstellungen umschaltet . Gleiches gilt für alle geschützten Datenklassen im Bereich Einstellungen → Datenschutz.

Nikita Kukushkin
quelle
Was ist mit der Autorisierung von Kamera und Fotogalerie?
Hajar ELKOUMIKHI
4

Schnelle Lösung

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

Und dann, um es zu benutzen, tun Sie es

AVCaptureDevice.authorizeVideo(completion: { (status) in
   //Your work here
})
Josh Bernfeld
quelle
Was ist mit der Autorisierung von Kamera und Fotogalerie?
Hajar ELKOUMIKHI
2

Als Ergänzung zur Antwort von @Raptor sollte Folgendes erwähnt werden. Ab iOS 10 wird möglicherweise die folgende Fehlermeldung angezeigt: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.

Um dies zu beheben, stellen Sie sicher, dass Sie die Ergebnisse des Hauptthreads wie folgt behandeln (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
                }
            }
        }
    }
}
Bart van Kuik
quelle
Im Falle einer Ablehnung funktioniert die requestAccess-Methode nicht. Sie müssen manuell eine Warnung anzeigen, um den Benutzer aufzufordern, zu den Einstellungen zu wechseln und Berechtigungen zu erteilen.
Abdullah Umer
0

Geben Sie zuerst den NSCameraUsageDescription-Schlüssel in Info.plist an. Überprüfen Sie dann AVAuthorizationStatus, falls autorisiert, und präsentieren Sie den UIImagePickerController. Es wird klappen.

Yogendra Singh
quelle
-4

Swift: Verwenden von AVFoundation

  1. Fügen Sie AVFoundation zum Ziel hinzu -> Phasen erstellen -> Binär mit Bibliotheken verknüpfen.
  2. AVFoundation auf ViewController importieren.
  3. Fügen Sie in Info.plist Folgendes hinzu:

Geben Sie hier die Bildbeschreibung ein

  1. On View Controller:

@IBAction func cameraButtonClicked (Absender: 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)
}
AG
quelle
Was ist mit den Info.plist-Einträgen? Quelle?
Bill