Anzeigen des Dialogfelds "Kameraberechtigung" in iOS 8

73

Wenn meine App unter iOS 8 zum ersten Mal versucht, auf die Kamera zuzugreifen, wird dem Benutzer ein Dialogfeld mit den Kameraberechtigungen angezeigt, ähnlich wie beim Mikrofon für den Mikrofonzugriff in iOS 7.

In iOS 7 war es möglich, den Mikrofonberechtigungsdialog vorher aufzurufen und zu prüfen, ob die Berechtigung erteilt wurde (siehe beispielsweise diese Frage ). Gibt es eine ähnliche Möglichkeit, den Kameraberechtigungsdialog in iOS 8 aufzurufen? Kann der Dialog für die Zugriffsberechtigung für Mikrofon UND Kamera kombiniert werden?

Jamix
quelle
Ich habe gerade eine Antwort gepostet, die sowohl den Kamera- als auch den Mikrofonzugriff überprüft und das Szenario erfasst, in dem Kameraberechtigungen erteilt werden, Mikrofonberechtigungen jedoch nicht.
Crashalot

Antworten:

90

Hier ist der Ansatz, den wir letztendlich verwendet haben:

if ([AVCaptureDevice respondsToSelector:@selector(requestAccessForMediaType: completionHandler:)]) {
    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
        // Will get here on both iOS 7 & 8 even though camera permissions weren't required 
        // until iOS 8. So for iOS 7 permission will always be granted.
        if (granted) {
            // Permission has been granted. Use dispatch_async for any UI updating
            // code because this block may be executed in a thread.
            dispatch_async(dispatch_get_main_queue(), ^{
                [self doStuff];
            });                
        } else {
            // Permission has been denied.
        }
    }];
} else {
    // We are on iOS <= 6. Just do what we need to do.
    [self doStuff];
}
Jamix
quelle
4
Ein kleiner Kommentar - Die requestAccessForMediaType-Methode ist auch in iOS 7 vorhanden (die Anforderung einer Kameraerlaubnis war damals nur in einigen Regionen von iOS erforderlich). Der andere Teil gilt also für <iOS 6.
Niraj
2
Die Codekommentare wurden aktualisiert, um nach einigen eigenen Tests etwas informativer / korrekter zu sein.
Stunner
In unseren Tests erfasst dieser Code nicht das Szenario, in dem Kameraberechtigungen erteilt werden, Mikrofonberechtigungen jedoch verweigert werden.
Crashalot
2
Dieser Code gilt nur für Kameraberechtigungen, die Gegenstand der ursprünglichen Frage sind.
Jamix
2
Für iOS 10+ Vergessen Sie nicht, die NSCameraUsageDescription in Ihre Liste aufzunehmen - zusammen mit dem Zweck, um die Erlaubnis zu bitten. Es wird abstürzen, wenn Sie dies nicht tun.
Jordan Hochstetler
62

Ich habe ein ähnliches Problem: Wenn der Benutzer den Kamerazugriff verweigert, wenn er zum ersten Mal dazu aufgefordert wird, führt das Drücken der Taste zum Aufnehmen eines Schnappschusses zu einem schwarzen Bildschirm im Kameramodus.

Ich möchte jedoch feststellen, dass der Benutzer den Zugriff abgelehnt hat, und ihn auffordern, ihn einzuschalten, aber ich kann keine Funktionen finden, um den aktuellen Zugriff der Benutzerkamera zu überprüfen. Gibt es eine solche Funktion?

BEARBEITEN: Die folgende Überprüfung informiert Sie in IOS 8 über den Kamerazugriff:

#import <AVFoundation/AVFoundation.h>

AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

    if(status == AVAuthorizationStatusAuthorized) { // authorized

    }
    else if(status == AVAuthorizationStatusDenied){ // denied

    }
    else if(status == AVAuthorizationStatusRestricted){ // restricted


    }
    else if(status == AVAuthorizationStatusNotDetermined){ // not determined

        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            if(granted){ // Access has been granted ..do something

            } else { // Access denied ..do something

            }
        }];
    }

Diese Informationen wurden in der folgenden Frage gefunden ( Woher wissen Sie, dass die Anwendung über Kamerazugriff verfügt oder nicht programmgesteuert in iOS8 ):

Raucher Husten
quelle
53

Hier ist meine Swift-Lösung (iOS 8). Ich brauchte die Kamera für das QR-Scannen, also musste ich sie wirklich auffordern.

Dies bietet

  1. Ermutigen Sie den Benutzer, Zulassen zu wählen, wenn vor der Standardeinstellung die Frage zum Zugriff auf die Kamera zulässig ist

  2. Einfache Möglichkeit, auf Einstellungen zuzugreifen, wenn der Benutzer die erste Anforderung abgelehnt hat.

Um es zum Laufen zu bringen, rufen Sie die Kamera in ViewDidAppear / oder ViewDidLoad usw. auf. Ich musste viewDidAppear verwenden, damit meine benutzerdefinierten Einschränkungen für Kameraansichten eingerichtet wurden.

func checkCamera() {
    let authStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
    switch authStatus {
    case .authorized: break // Do your stuff here i.e. allowScanning()
    case .denied: alertToEncourageCameraAccessInitially()
    case .notDetermined: alertPromptToAllowCameraAccessViaSetting()
    default: alertToEncourageCameraAccessInitially()
    }
}

func alertToEncourageCameraAccessInitially() {
    let alert = UIAlertController(
        title: "IMPORTANT",
        message: "Camera access required for QR Scanning",
        preferredStyle: UIAlertControllerStyle.alert
    )
    alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
    alert.addAction(UIAlertAction(title: "Allow Camera", style: .cancel, handler: { (alert) -> Void in
        UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!)
    }))
    present(alert, animated: true, completion: nil)
}

func alertPromptToAllowCameraAccessViaSetting() {

    let alert = UIAlertController(
        title: "IMPORTANT",
        message: "Please allow camera access for QR Scanning",
        preferredStyle: UIAlertControllerStyle.alert
    )
    alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel) { alert in
        if AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo).count > 0 {
            AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { granted in
                DispatchQueue.main.async() {
                    self.checkCamera() } }
        }
        }
    )
    present(alert, animated: true, completion: nil)
}

Dank jamix oben für den Tipp zur Verwendung von dispatch_async - macht die Reaktion auf die Anzeige der neu eingestellten Kamerafunktion so viel schneller.

Entschuldigung für eine Mischung aus nachlaufenden Verschlüssen. Ich wollte sie ausprobieren.

DogCoffee
quelle
Ich bin hier wählerisch / neugierig, aber warum stellst du style: .Defaultden CancelKnopf und style: .Cancelden anderen Knopf ein? Ist es nur ein Fehler oder machst du es mit einem Zweck?
SaltyNuts
Ich glaube, ich wollte nur, dass einer mehr hervorsticht als der andere, das ist alles. Wie fett gegen normale Schrift.
DogCoffee
@DogCoffee Ich bin etwas verwirrt über die Berechtigungsaufforderung für den anfänglichen Zugriff auf die Kamera. Ist das nicht etwas mit iOS integriertes, das die Entwickler nicht nachahmen können? Wir können nur überprüfen, ob es vorher abgelehnt wurde und dann auffordern, in den Einstellungen zu aktualisieren?
user2363025
Ich habe das vor einiger Zeit gemacht, die App brauchte die Kamera für meinen QR-Reader. iOS fragt, ob die Kamera verwendet werden kann. Ich wollte nur, dass der Benutzer weiß warum. Die meiste Zeit, wenn Dinge auftauchen, die nach diesem oder jenem fragen, das ich selbst kenne, leugne ich normalerweise zuerst. Dies war nur meine Art zu sagen - hübsch, bitte akzeptiere.
DogCoffee
@DogCoffee Ich muss also keine Funktion für die Eingabeaufforderung für die erstmalige Zugriffsberechtigung erstellen. Ich kann iOS dies im Hintergrund tun lassen und muss nur darauf achten, ob sie in der Vergangenheit Berechtigungen verweigert haben.
user2363025
16

Keine der Antworten scheint die Berechtigungen für Mikrofone und Kameras zu überprüfen. Unser Code vergleicht das Szenario, in dem Kameraberechtigungen erteilt werden, der Mikrofonzugriff jedoch verweigert wird.

Da wir Swift noch nicht kennen, ist es unwahrscheinlich, dass die knorrig verschachtelten Abschlüsse und ifAnweisungen optimal sind. Bitte teilen Sie Vorschläge zur Verbesserung des Codes! Aber zumindest funktioniert es bisher beim Testen.

    AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (videoGranted: Bool) -> Void in
        if (videoGranted) {
            AVCaptureDevice.requestAccessForMediaType(AVMediaTypeAudio, completionHandler: { (audioGranted: Bool) -> Void in
                if (audioGranted) {
                    dispatch_async(dispatch_get_main_queue()) {
                        // Both video & audio granted
                    }
                } else {
                    // Rejected audio
                }
            })
        } else {
            // Rejected video
        }
    })
Crashalot
quelle
1
Beantworten Sie nur Antworten, die sowohl Video- als auch Audioberechtigungen betreffen. Randnotiz, es ist verrückt für mich, dass Sie nicht beide als Kombination verlangen können, danke Apfel.
Übersetzung
Dies ist die richtige Antwort. Für die Videoaufzeichnung ist dies von entscheidender Bedeutung, da das System sonst beim Initialisieren der Sitzung selbst Audioberechtigungen startet. Dann wird Ihre App nichts davon wissen und es "bastelt" im Wesentlichen die Erfahrung für den Benutzer. Ich habe bemerkt, dass viele Projekte dies einfach ignorieren und Junge, Junge, generiert es eine große Anzahl von Kunden-Support-Tickets :)
Ryan Romanchuk
8
  • Swift 3.0-Lösung

    AVFoundation importieren

Hinweis: Fügen Sie in Ihrer Info.plist den Schlüssel Privacy - Camera Usage Description hinzu

// MARK: Kamerahandhabung

        func callCamera(){
            let myPickerController = UIImagePickerController()
            myPickerController.delegate = self;
            myPickerController.sourceType = UIImagePickerControllerSourceType.camera

            self.present(myPickerController, animated: true, completion: nil)
            NSLog("Camera");
        }
        func checkCamera() {
            let authStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
            switch authStatus {
            case .authorized: callCamera() // Do your stuff here i.e. callCameraMethod()
            case .denied: alertToEncourageCameraAccessInitially()
            case .notDetermined: alertPromptToAllowCameraAccessViaSetting()
            default: alertToEncourageCameraAccessInitially()
            }
        }

        func alertToEncourageCameraAccessInitially() {
            let alert = UIAlertController(
                title: "IMPORTANT",
                message: "Camera access required for capturing photos!",
                preferredStyle: UIAlertControllerStyle.alert
            )
            alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
            alert.addAction(UIAlertAction(title: "Allow Camera", style: .cancel, handler: { (alert) -> Void in
                UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!)
            }))
            present(alert, animated: true, completion: nil)
        }

        func alertPromptToAllowCameraAccessViaSetting() {

            let alert = UIAlertController(
                title: "IMPORTANT",
                message: "Camera access required for capturing photos!",
                preferredStyle: UIAlertControllerStyle.alert
            )
            alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel) { alert in
                if AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo).count > 0 {
                    AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { granted in
                        DispatchQueue.main.async() {
                            self.checkCamera() } }
                }
                }
            )
            present(alert, animated: true, completion: nil)
        }
Sourabh Sharma
quelle
Sie haben die Methoden gewechselt ;-) Die 'Via-Einstellung' startet den Perm-Dialog und die zweite startet die Einstellungen :-)
Matrejek
5

Für Swift 3 können Sie dies zu Ihrer viewWillAppearMethode Ihres ersten Ansichtscontrollers hinzufügen :

Importieren Sie zuerst das AVFoundationFramework

import AVFoundation

Dann:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let authorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)

    switch authorizationStatus {
    case .notDetermined:
        AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { granted in
            if granted {
                print("access granted")
            }
            else {
                print("access denied")
            }
        }
    case .authorized:
        print("Access authorized")
    case .denied, .restricted:
        print("restricted")

    }
}

Vergessen Sie nicht, Privacy - Camera Usage DescriptionIhren Schlüssel hinzuzufügenInfo.plist

Pableiros
quelle
4

Für mich funktioniert diese Arbeit auf iOS7 und iOS8:

    ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];

    switch (status) {
        case ALAuthorizationStatusAuthorized:
            break;

        case ALAuthorizationStatusRestricted:
        case ALAuthorizationStatusDenied:
            break;

        case ALAuthorizationStatusNotDetermined:
            break;
    }
konfile
quelle
3
Es wirkt wie ein Zauber. Vergessen Sie nicht den Import:#import <AssetsLibrary/AssetsLibrary.h>
Erzékiel
Funktioniert unter IOS 9 nicht mehr, da ALAssetsLibrary veraltet ist.
Supertecnoboff
3

Ich mache eine Zugriffsprüfung für den App-Delegaten.

import UIKit
import AVFoundation
import Photos

        func applicationDidBecomeActive(application: UIApplication) {
            cameraAllowsAccessToApplicationCheck()
            internetAvailabilityOnApplicationCheck()
            photoLibraryAvailabilityCheck()
        }

    //MARK:- CAMERA ACCESS CHECK
        func cameraAllowsAccessToApplicationCheck()
        {
            let authorizationStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)
            switch authorizationStatus {
            case .NotDetermined:
                // permission dialog not yet presented, request authorization
                AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo,
                    completionHandler: { (granted:Bool) -> Void in
                        if granted {
                            print("access granted")
                        }
                        else {
                            print("access denied")
                        }
                })
            case .Authorized:
                print("Access authorized")
            case .Denied, .Restricted:
            alertToEncourageCameraAccessWhenApplicationStarts()
            default:
                print("DO NOTHING")
            }
        }
        //MARK:- PHOTO LIBRARY ACCESS CHECK
        func photoLibraryAvailabilityCheck()
        {
            if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.Authorized
            {

            }
            else
            {
                var cameraUnavailableAlertController = UIAlertController (title: "Photo Library Unavailable", message: "Please check to see if device settings doesn't allow photo library access", preferredStyle: .Alert)

                var settingsAction = UIAlertAction(title: "Settings", style: .Destructive) { (_) -> Void in
                    let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
                    if let url = settingsUrl {
                        UIApplication.sharedApplication().openURL(url)
                    }
                }
                var cancelAction = UIAlertAction(title: "Okay", style: .Default, handler: nil)
                cameraUnavailableAlertController .addAction(settingsAction)
                cameraUnavailableAlertController .addAction(cancelAction)
                self.window?.rootViewController!.presentViewController(cameraUnavailableAlertController , animated: true, completion: nil)
            }
        }
        func internetAvailabilityOnApplicationCheck()
        {
            //MARK:- INTERNET AVAILABLITY
            if InternetReachability.isConnectedToNetwork() {

            }
            else
            {
                dispatch_async(dispatch_get_main_queue(), {

                    //INTERNET NOT AVAILABLE ALERT
                    var internetUnavailableAlertController = UIAlertController (title: "Network Unavailable", message: "Please check your internet connection settings and turn on Network Connection", preferredStyle: .Alert)

                    var settingsAction = UIAlertAction(title: "Settings", style: .Destructive) { (_) -> Void in
                        let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
                        if let url = settingsUrl {
                            UIApplication.sharedApplication().openURL(url)
                        }
                    }
                    var cancelAction = UIAlertAction(title: "Okay", style: .Default, handler: nil)
                    internetUnavailableAlertController .addAction(settingsAction)
                    internetUnavailableAlertController .addAction(cancelAction)
                    self.window?.rootViewController!.presentViewController(internetUnavailableAlertController , animated: true, completion: nil)
                })
            }
        }

* *

AG
quelle
2

Das Problem für mich war , dass Bundle nameund Bundle Display Namewaren nicht in meinem Info.plist aufgrund einiger letzten Build - Konfigurationsänderungen festgelegt zu werden . Ein unwahrscheinlicher Fall ... Aber ich habe ein paar Stunden gebraucht, um das festzunageln. Hoffentlich hilft es jemand anderem.

Chris Wagner
quelle