web-dev-qa-db-fra.com

Détecter la permission de la caméra sous iOS

Je développe une application vidéo très simple. J'utilise le contrôle officiel: UIImagePickerController.

Voici le problème. Lors de la présentation de UIImagePickerController pour la première fois, iOS demandera l'autorisation. L'utilisateur peut cliquer sur oui ou non. Si l'utilisateur clique sur non, le contrôle n'est pas rejeté. Au lieu de cela, si l'utilisateur continue de cliquer sur le bouton de démarrage, les minuteries sont allumées alors que l'écran est toujours noir et l'utilisateur ne peut ni les arrêter ni revenir en arrière. La seule chose que l'utilisateur puisse faire est de tuer l'application. La prochaine fois que UIImagePickerController est présenté, l'écran reste noir et l'utilisateur ne peut pas revenir en arrière s'il clique sur démarrer.

Je me demandais si c'était un bug. Existe-t-il un moyen de détecter l'autorisation de la caméra afin de décider de montrer ou non le UIImagePickerController?

135
user418751

Vérifiez la AVAuthorizationStatus et gérez les cas correctement.

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
}
221
Raptor

Depuis iOS 10, vous devez spécifier la clé NSCameraUsageDescription dans votre Info.plist pour pouvoir demander un accès à la caméra. Sinon, votre application se bloquera au moment de l'exécution. Voir API nécessitant des descriptions d'utilisation .


Assurez-vous de:

import AVFoundation

Le code Swift ci-dessous vérifie tous les états d'autorisation possibles:

Swift 4 et plus récent

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

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

Comme note intéressante, saviez-vous qu'iOS tue l'application si elle est en cours d'exécution pendant que vous modifiez ses autorisations d'appareil photo dans les paramètres?

Depuis le forum Apple Developer:

Le système tue réellement votre application si l'utilisateur change l'accès de votre application à caméra dans les paramètres. Il en va de même pour toute classe de données protégée dans la section Paramètres → Confidentialité.

76
Nikita Kukushkin

En complément de la réponse de @Raptor, il convient de mentionner les éléments suivants. Le message d'erreur suivant commençant par iOS 10 peut s'afficher: 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.

Pour résoudre ce problème, assurez-vous de gérer les résultats du thread principal comme suit (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
                }
            }
        }
    }
}
2
Bart van Kuik

Solution rapide

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

Et puis, pour l'utiliser, vous faites

AVCaptureDevice.authorizeVideo(completion: { (status) in
   //Your work here
})
2
Josh Bernfeld

Spécifiez d'abord la clé NSCameraUsageDescription dans Info.plist. Puis vérifiez si AVAuthorizationStatus est autorisé puis présentez le UIImagePickerController. Ça va marcher.

0
Yogendra Singh