Как сохранить контакт в приложении "Контакты" в iOS - Swift

Я пытаюсь сохранить контакт в приложении контактов, используя этот код напрямую, не запрашивая разрешения:

import Foundation
import UIKit
import Contacts

@available(iOS 9.0, *)
class OnCallEmpContact: UITableViewController {

    var store: CNContactStore!

    @IBOutlet weak var nameLabel: UILabel!

    @IBOutlet weak var phoneLabel: UILabel!

    @IBOutlet weak var emailLabel: UILabel!

    @IBOutlet weak var workPhoneLabel: UILabel!



    var emp = employee()
    var rank = ""

    override func viewDidLoad() {
        super.viewDidLoad()
        self.nameLabel.text=self.emp.getFistName()+" "+emp.getLastName()
        self.phoneLabel.text="0"+self.emp.getMobile()
        self.emailLabel.text=self.emp.getEmail()
        self.workPhoneLabel.text=self.emp.getPhone()

        store = CNContactStore()
        checkContactsAccess()


    }

    private func checkContactsAccess() {
        switch CNContactStore.authorizationStatusForEntityType(.Contacts) {
            // Update our UI if the user has granted access to their Contacts
        case .Authorized:
            self.accessGrantedForContacts()

            // Prompt the user for access to Contacts if there is no definitive answer
        case .NotDetermined :
            self.requestContactsAccess()

            // Display a message if the user has denied or restricted access to Contacts
        case .Denied,
        .Restricted:
            let alert = UIAlertController(title: "Privacy Warning!",
                message: "Permission was not granted for Contacts.",
                preferredStyle: .Alert)
            alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
            self.presentViewController(alert, animated: true, completion: nil)
        }
    }

    private func requestContactsAccess() {

        store.requestAccessForEntityType(.Contacts) {granted, error in
            if granted {
                dispatch_async(dispatch_get_main_queue()) {
                    self.accessGrantedForContacts()
                    return
                }
            }
        }
    }

    // This method is called when the user has granted access to their address book data.
    private func accessGrantedForContacts() {
        //Update UI for grated state.
        //...
    }


    override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if section == 0{
        if rank == "0"{
        return "Primary Employee"
        }
        else if rank == "1"{
        return "Backup Employee"
        }
        }
        return""
    }

    override  func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

        tableView.deselectRowAtIndexPath(indexPath, animated: true) // to stop highliting the selected cell

        if indexPath.section==1 && indexPath.row==0{
                self.saveContact()
        }


    }



    func saveContact(){
        do{
            let contact = CNMutableContact()
        contact.givenName = self.emp.getFistName()
        contact.familyName = self.emp.getLastName()
        contact.phoneNumbers = [CNLabeledValue(
            label:CNLabelPhoneNumberiPhone,
            value:CNPhoneNumber(stringValue:emp.getMobile())),
                  CNLabeledValue(
                label:CNLabelPhoneNumberiPhone,
                value:CNPhoneNumber(stringValue:emp.getPhone()))]

        let workEmail = CNLabeledValue(label:CNLabelWork, value:emp.getEmail())
        contact.emailAddresses = [workEmail]


        let saveRequest = CNSaveRequest()
        saveRequest.addContact(contact, toContainerWithIdentifier:nil)
        try store.executeSaveRequest(saveRequest)
            print("saved")

        }

        catch{
            print("error")
        }
    }



}

Я получаю сообщение об ошибке в последней строке try store.executeSaveRequest(saveRequest) метода saveContact

Ошибка :

фатальная ошибка: "попробуйте!" выражение неожиданно вызвало ошибку: Error Domain = CNErrorDomain Code = 100 «Доступ запрещен» UserInfo = {NSLocalizedDescription = Access Denied, NSLocalizedFailureReason = Этому приложению не предоставлено разрешение на доступ к контактам.

Я нашел приведенный выше код на веб-сайте Apple, но также выделил его в разделе «Конфиденциальность» посередине:

Любой вызов CNContactStore заблокирует приложение, пока пользователя просят предоставить или запретить доступ.

Но ничего не появляется с запросом на доступ к приложению контактов ... я должен написать еще код для этого? Как ?


person Zizoo    schedule 03.09.2016    source источник


Ответы (3)


Это не правильно! Используйте оператор _1 _-_ 2_, и все будет в порядке.

do {
  try store.executeSaveRequest(saveRequest)
} catch {}

Надеюсь, поможет.

person Mannopson    schedule 04.09.2016
comment
Я уже пробую это, не работает, каждый раз будет попадать в улов - person Zizoo; 04.09.2016

Это новейший синтаксис от swift. Надеюсь, поможет !

           let store = CNContactStore()

            if CNContactStore.authorizationStatus(for: .contacts) == .notDetermined {
                store.requestAccess(for: .contacts) {granted, error in
                    if granted {
                        print("PERMISSION GRANTED")
                    } else {
                        print("PERMISSION NOT GRANTED")
                    }
                }
            } else if CNContactStore.authorizationStatus(for: .contacts) == .authorized {
                // If the user user has earlier provided the access, then add the contact
                print("AUTHORIZED")

                findContactsOnBackgroundThread { (contact) in
                    print("contacts : ",contact as Any)
                }
            } else {
                // If the user user has NOT earlier provided the access, create an alert to tell the user to go to Settings app and allow access
                print("NOT AUTHORIZED")
            }
person Daniel Wijono    schedule 11.02.2019

Возможно, вы читали Справочник по структуре контактов. Вы должны подумать, что такое общее описание может быть неточным в деталях. Проверить последнюю ссылку.

CNContactStore имеет два метода авторизации:

Доступ к конфиденциальности

+ authorizationStatusForEntityType:

- requestAccessForEntityType: completionHandler:

Вы должны написать что-то вроде этого в своем приложении:

var store: CNContactStore!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    store = CNContactStore()
    checkContactsAccess()
}

private func checkContactsAccess() {
    switch CNContactStore.authorizationStatusForEntityType(.Contacts) {
    // Update our UI if the user has granted access to their Contacts
    case .Authorized:
        self.accessGrantedForContacts()
        
    // Prompt the user for access to Contacts if there is no definitive answer
    case .NotDetermined :
        self.requestContactsAccess()
        
    // Display a message if the user has denied or restricted access to Contacts
    case .Denied,
         .Restricted:
        let alert = UIAlertController(title: "Privacy Warning!",
                                      message: "Permission was not granted for Contacts.",
                                      preferredStyle: .Alert)
        alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
        self.presentViewController(alert, animated: true, completion: nil)
    }
}

private func requestContactsAccess() {
    
    store.requestAccessForEntityType(.Contacts) {granted, error in
        if granted {
            dispatch_async(dispatch_get_main_queue()) {
                self.accessGrantedForContacts()
                return
            }
        }
    }
}

// This method is called when the user has granted access to their address book data.
private func accessGrantedForContacts() {
    //Update UI for grated state.
    //...
}
person OOPer    schedule 04.09.2016
comment
Спасибо, но когда приложение достигает requestContactsAccess (), почему оно не запрашивает запрос к пользователю? + где вызвать мою функцию saveContact ()? - person Zizoo; 04.09.2016
comment
@Zizoo, просто я предполагаю, что когда вы впервые использовали приложение, вы могли отклонить или разрешить, а сим или устройство сохраняют состояние. Проверьте настройки ›Конфиденциальность› Контакты или попробуйте использовать новую сим-карту или устройство. Для последнего добавьте в приложение кнопку сохранения и вызовите метод в методе @IBAction. Еще одно: лучше не использовать try! в реальных приложениях. Используйте простой try в do {} catch {}. - person OOPer; 04.09.2016
comment
хорошо, что этот метод использовал для 'accessGrantedForContacts', потому что я беру информацию о контакте от объекта сотрудника, который у меня есть, и когда кнопка нажата, я вызываю функцию сохранения, извините, я новичок в iOS - person Zizoo; 04.09.2016
comment
Я использовал ваш код, но по-прежнему ничего не появляется, запрашивая доступ, также я сменил сим-карту, но все еще не работает и получаю ту же ошибку, что доступ запрещен. - person Zizoo; 04.09.2016
comment
@Zizoo, если вы используете мой checkContactsAccess, вы должны увидеть предупреждение о конфиденциальности! предупреждение в запрещенном состоянии. Так что это действительно странное поведение. Можете ли вы показать мне версии вашего Xcode и симуляторы, которые вы использовали? - person OOPer; 04.09.2016
comment
Да, я вижу предупреждение о конфиденциальности, но не запрашиваю запрос к контактам - person Zizoo; 04.09.2016
comment
Xcode Version 7.2.1, я использовал sim: Version 9.2 (SimulatorApp-643 CoreSimulator-201.3) - person Zizoo; 04.09.2016
comment
Если вы видите это предупреждение о конфиденциальности !, значит, ваш сим сохраняет состояние отказа для вашего приложения. Попробуйте «Сбросить содержимое и настройки ...» в меню «Симулятор», чтобы очистить состояние (или выберите другой совершенно новый симулятор). А в запрещенном состоянии вам необходимо отключить все пользовательские интерфейсы (например, кнопки сохранения), чтобы предотвратить доступ к CNContactStore. Любой доступ к CNContactStore в запрещенном состоянии может вызвать ту же ошибку, что и вы видели. - person OOPer; 04.09.2016
comment
Я сменил симку .. Код сначала переходит в viewDidLoad checkContactsAccess(), затем в case NotDetermined, затем переходит к requestContactsAccess(), и ничего не появляется, запрашивая запрос, затем я возвращаюсь с помощью кнопки навигации в режим предварительного просмотра и снова перехожу в режим просмотра2, и я получаю предупреждение, теперь он продолжает регистрировать Denied,.Restricted - person Zizoo; 04.09.2016
comment
@Zizoo, я не понимаю вашу кнопку навигации для предварительного просмотра view или view2, но мой код взят из реально работающего образца кода. Так что то, что не показано, могло бы повлиять на это, но я не могу больше ничего сказать, не увидев их, и я понятия не имею, что я должен попросить вас показать мне на данный момент. - person OOPer; 04.09.2016
comment
Извините, но я думаю, что система чата - худшая вещь в SO, просто мне она не нравится. Если вы добавили в свой вопрос дополнительную информацию, которая мне нужна, я посмотрю. - person OOPer; 04.09.2016
comment
@Zizoo, я попробовал ваш код (точно такой же, ни один символ не изменен) в качестве второго контроллера представления (заполнил некоторые другие части), и я получаю "MyAppName" Would Like to Access Your Contacts диалог с Don't Allow и OK при его первом использовании. Проблема может скрываться в других частях вашего кода. - person OOPer; 04.09.2016
comment
Спасибо за помощь .. но вы не видели мой код ничего плохого с ним, может проблема с сим .. - person Zizoo; 04.09.2016
comment
Проверять доступ к контактам в viewDidLoad еще рано. Попробуйте в viewDidAppear. Затем предупреждение может быть представлено без предупреждения.Представление контроллеров представления на контроллерах отсоединенного представления не рекомендуется (iOS10.3 +) - person ghr; 26.04.2020