web-dev-qa-db-fra.com

Demander l'accès aux contacts en Swift 3

Je souhaite accéder aux contacts de l'utilisateur et je prévois de le faire en utilisant le cadre Contacts et ContactsUI fourni Apple fournitures.

Cependant, je dois d'abord demander la permission d'accéder aux contacts de l'utilisateur et j'ai du mal à le faire. Dans Swift 2, on pourrait demander la permission comme ceci:

func requestForAccess(completionHandler: (accessGranted: Bool) -> Void) {
    let authorizationStatus = CNContactStore.authorizationStatusForEntityType(CNEntityType.Contacts)

    switch authorizationStatus {
    case .Authorized:
        completionHandler(accessGranted: true)

    case .Denied, .NotDetermined:
        self.contactStore.requestAccessForEntityType(CNEntityType.Contacts, completionHandler: { (access, accessError) -> Void in
            if access {
                completionHandler(accessGranted: access)
            }
            else {
                if authorizationStatus == CNAuthorizationStatus.Denied {
                    dispatch_async(dispatch_get_main_queue(), { () -> Void in 
                        let message = "\(accessError!.localizedDescription)\n\nPlease allow the app to access your contacts through the Settings."
                        self.showMessage(message)
                    })
                }
            }
        })

    default:
        completionHandler(accessGranted: false)
    }
}

J'ai essayé de le convertir en Swift 3 comme ça, mais je rencontre toujours des erreurs. L'erreur est "Le membre d'instance 'async' ne peut pas être utilisé sur le type 'DispatchQueue'; vouliez-vous utiliser une valeur de ce type à la place? ":

func requestForAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void) {
    let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts)

    switch authorizationStatus {
    case .authorized:
        completionHandler(true)

    case .denied, .notDetermined:
        self.contactStore.requestAccess(for: CNEntityType.contacts, completionHandler: { (access, accessError) -> Void in
            if access {
                completionHandler(access)
            }
            else {
                if authorizationStatus == CNAuthorizationStatus.denied {
                    DispatchQueue.async(group: DispatchQueue.main, execute: { () -> Void in //error here
                        let message = "\(accessError!.localizedDescription)\n\nPlease allow the app to access your contacts through the Settings."
                        self.showMessage(message)
                    })
                }
            }
        })

    default:
        completionHandler(false)
    }
}

Quelqu'un peut-il aider à résoudre ce problème? Toute aide serait grandement appréciée. Merci une tonne à l'avance.

À la vôtre, Theo

10
Theo Strauss

Au lieu de

DispatchQueue.async(group: DispatchQueue.main, execute: { ... }

faire

DispatchQueue.main.async { ... }

Soit dit en passant, si l'autorisation avait déjà été refusée, il est inutile de demander à nouveau l'autorisation, car le système d'exploitation ne présentera aucune interface utilisateur "d'accorder l'accès" à l'utilisateur final. Il ne le fait que si l'utilisateur n'a pas précédemment refusé l'accès.

Si l'accès aux contacts est vraiment essentiel au bon fonctionnement de l'application, vous pouvez leur montrer une alerte qui leur donne la possibilité d'accéder aux paramètres directement depuis votre application:

func requestAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void) {
    switch CNContactStore.authorizationStatus(for: .contacts) {
    case .authorized:
        completionHandler(true)
    case .denied:
        showSettingsAlert(completionHandler)
    case .restricted, .notDetermined:
        store.requestAccess(for: .contacts) { granted, error in
            if granted {
                completionHandler(true)
            } else {
                DispatchQueue.main.async {
                    self.showSettingsAlert(completionHandler)
                }
            }
        }
    }
}

private func showSettingsAlert(_ completionHandler: @escaping (_ accessGranted: Bool) -> Void) {
    let alert = UIAlertController(title: nil, message: "This app requires access to Contacts to proceed. Would you like to open settings and grant permission to contacts?", preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "Open Settings", style: .default) { action in
        completionHandler(false)
        UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)!)
    })
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { action in
        completionHandler(false)
    })
    present(alert, animated: true)
}
28
Rob