【问题标题】:Request Access To Contacts in Swift 3请求访问 Swift 3 中的联系人
【发布时间】:2017-08-30 17:59:54
【问题描述】:

我想访问用户的联系人并计划使用 Apple 提供的 Contacts 和 ContactsUI 框架。

不过,首先,我需要获得访问用户联系人的权限,但我在这样做时遇到了麻烦。在 Swift 2 中,可以像这样请求许可:

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

我尝试像这样将其转换为 Swift 3,但仍然出现错误。错误是“Instance member 'async' cannot be used on type 'DispatchQueue';你的意思是改用这种类型的值吗?”:

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

谁能帮忙解决这个问题?任何帮助将不胜感激。提前致谢。

干杯, 西奥

【问题讨论】:

  • 出现了哪些错误?
  • “我仍然想出错误”不是一个问题。清楚地说明“错误”是什么以及在哪一行。另外,你真的想象在 Stack Overflow 之前没有人讨论过如何在 Swift 3 中授权联系人访问吗?在询问之前尝试搜索。节省带宽。
  • @matt 我认为堆栈溢出不需要这种攻击性。我添加了错误,但只是冷静下来
  • @GIJOW 添加在上面。 “实例成员 'async' 不能用于类型 'DispatchQueue';您的意思是使用这种类型的值来代替吗?”

标签: ios swift swift3 contacts


【解决方案1】:

代替

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

做

DispatchQueue.main.async { ... }

顺便说一句,如果权限之前被拒绝,那么再次请求授权是没有意义的,因为操作系统不会向最终用户显示任何“授予访问权限”的 UI。只有在用户之前没有拒绝访问的情况下才会这样做。

如果访问通讯录对于应用的成功运行确实必不可少,您可以向他们显示一条提醒,让他们可以选择直接从您的应用转到“设置”:

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. Go to Settings to grant access.", preferredStyle: .alert)
    if
        let settings = URL(string: UIApplication.openSettingsURLString),
        UIApplication.shared.canOpenURL(settings) { 
            alert.addAction(UIAlertAction(title: "Open Settings", style: .default) { action in
                completionHandler(false)
                UIApplication.shared.open(settings)
            })
    }
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { action in
        completionHandler(false)
    })
    present(alert, animated: true)
}

【讨论】:

  • 非常感谢!你会建议删除我拥有的整个功能并用它替换它吗?或在其上添加 showFunctionsAlert()。
  • 我不确定我是否听懂了你的问题。但这会请求访问以及在被拒绝时显示警报,所以我不确定您还需要什么。
  • 顺便说一句,我调整了我的答案以采用闭包参数,就像你原来的例子一样。我最初的示例是在视图出现时请求授权,但最好将这个问题推迟到用户真正需要访问权限的时候(可能是在视图出现时,但更有可能是当他们点击显然需要联系人的东西时; 如果您将其推迟到可能的最晚时间,则用户更有可能与您的应用互动并且更有可能授予权限。
  • 嘿,抱歉在我看到您的编辑之前发表了评论。我在问我是否应该在我最初的问题中包含我的功能和上面的两个功能。或者您在答案中提供的功能足以要求用户许可。非常感谢所有的帮助
  • 我明白你现在的目标是什么。我正准备点击复选标记,但还有一个问题。我应该在 viewdidload 中调用这两个函数还是不需要。非常感谢
【解决方案2】:

同样的事情,真的,但它把 no 视为 no,而不是也许,不是现在或类似的东西。您是否在 Apple 隐私提示中看到任何模糊逻辑?我没有。

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

    switch authorizationStatus {
    case .authorized:
        completionHandler(true)

    case .notDetermined:
        self.contactStore.requestAccess(for: CNEntityType.contacts, completionHandler: { (access, accessError) -> Void in
            if access {
                completionHandler(access)
            }
            else {
                completionHandler(false)
            }
        })

    default:
        completionHandler(false)
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 2011-07-11
    • 2013-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多