Programmatically add contact in Swift
Asked Answered
M

4

15

I want to add a contact (just the name and phone number) programatically in Swift. I've found some Objective-C examples but I didn't get them to work, not even in Objective-C. I don't want this to involve AddressBookUI, because I want to get the values from my own UI.

Mickens answered 26/6, 2014 at 11:20 Comment(0)
C
10

Here's a quick method to add a contact in Swift. I verified it on my iPhone 5 iOS 7.1 as I've found the simulator doesn't always match the same results as my phone does for AB stuff.

You can add a button and point to this method:

@IBAction func createContact(sender: AnyObject) {
    var newContact:ABRecordRef! = ABPersonCreate().takeRetainedValue()
    var success:Bool = false
    var newFirstName:NSString = "AA"
    var newLastName = "a"

//Updated to work in Xcode 6.1
        var error: Unmanaged<CFErrorRef>? = nil
//Updated to error to &error so the code builds in Xcode 6.1
    success = ABRecordSetValue(newContact, kABPersonFirstNameProperty, newFirstName, &error)
    println("setting first name was successful? \(success)")
    success = ABRecordSetValue(newContact, kABPersonLastNameProperty, newLastName, &error)
    println("setting last name was successful? \(success)")
    success = ABAddressBookAddRecord(adbk, newContact, &error)
    println("Adbk addRecord successful? \(success)")
    success = ABAddressBookSave(adbk, &error)
    println("Adbk Save successful? \(success)")

}//createContact

btw-it assumes you've already got an addressbook var assigned, which you can on opening the view by overriding viewDidAppear. It does the security prompt as well:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    if !self.authDone {
        self.authDone = true
        let stat = ABAddressBookGetAuthorizationStatus()
        switch stat {
        case .Denied, .Restricted:
            println("no access")
        case .Authorized, .NotDetermined:
            var err : Unmanaged<CFError>? = nil
            var adbk : ABAddressBook? = ABAddressBookCreateWithOptions(nil, &err).takeRetainedValue()
            if adbk == nil {
                println(err)
                return
            }
            ABAddressBookRequestAccessWithCompletion(adbk) {
                (granted:Bool, err:CFError!) in
                if granted {
                    self.adbk = adbk
                } else {
                    println(err)
                }//if
            }//ABAddressBookReqeustAccessWithCompletion
        }//case
    }//if
}//viewDidAppear
Chancellorship answered 31/8, 2014 at 2:17 Comment(3)
Good answer. BTW, where you call ABAddressBookCreateWithOptions, though, your err is unmanaged, so unless you call takeRetainedValue() for the err, this will leak. Likewise, where you're setting the properties of the ABRecordRef, (a) I think you can eliminate that UnsafeMutablePointer and just use var error: Unmanaged<CFErrorRef>?; and (b) if any of these lines generate an error, you'll want to likewise want to takeRetainedValue.Magnetize
Thanks - I spent an hour learning what Unmanaged was the other day so I finally understand what you wrote here :) developer.apple.com/library/prerelease/ios/documentation/Swift/…Chancellorship
Figured out how to resolve the Xcode 6.1 error that Rob highlighted months ago. Changing to his suggested syntax, and instead of passing in error as a param, passing in &error, a pointer.Chancellorship
A
11

Swift 4 & 5

import ContactsUI

Inherit this class CNContactViewControllerDelegate

@IBOutlet var contactNameTxt: UITextField!
@IBOutlet var phoneNumberTxt: UITextField!

@IBAction func saveActionBtn(_ sender: UIButton) {

        let store = CNContactStore()
        let contact = CNMutableContact()

        // Name
        contact.givenName = contactNameTxt.text ?? ""

        // Phone
        contact.phoneNumbers.append(CNLabeledValue(
            label: "mobile", value: CNPhoneNumber(stringValue: phoneNumberTxt.text ?? "")))

        // Save
        let saveRequest = CNSaveRequest()
        saveRequest.add(contact, toContainerWithIdentifier: nil)
        try? store.execute(saveRequest)
}

enter image description here

Anabal answered 27/9, 2019 at 6:28 Comment(0)
C
10

Here's a quick method to add a contact in Swift. I verified it on my iPhone 5 iOS 7.1 as I've found the simulator doesn't always match the same results as my phone does for AB stuff.

You can add a button and point to this method:

@IBAction func createContact(sender: AnyObject) {
    var newContact:ABRecordRef! = ABPersonCreate().takeRetainedValue()
    var success:Bool = false
    var newFirstName:NSString = "AA"
    var newLastName = "a"

//Updated to work in Xcode 6.1
        var error: Unmanaged<CFErrorRef>? = nil
//Updated to error to &error so the code builds in Xcode 6.1
    success = ABRecordSetValue(newContact, kABPersonFirstNameProperty, newFirstName, &error)
    println("setting first name was successful? \(success)")
    success = ABRecordSetValue(newContact, kABPersonLastNameProperty, newLastName, &error)
    println("setting last name was successful? \(success)")
    success = ABAddressBookAddRecord(adbk, newContact, &error)
    println("Adbk addRecord successful? \(success)")
    success = ABAddressBookSave(adbk, &error)
    println("Adbk Save successful? \(success)")

}//createContact

btw-it assumes you've already got an addressbook var assigned, which you can on opening the view by overriding viewDidAppear. It does the security prompt as well:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    if !self.authDone {
        self.authDone = true
        let stat = ABAddressBookGetAuthorizationStatus()
        switch stat {
        case .Denied, .Restricted:
            println("no access")
        case .Authorized, .NotDetermined:
            var err : Unmanaged<CFError>? = nil
            var adbk : ABAddressBook? = ABAddressBookCreateWithOptions(nil, &err).takeRetainedValue()
            if adbk == nil {
                println(err)
                return
            }
            ABAddressBookRequestAccessWithCompletion(adbk) {
                (granted:Bool, err:CFError!) in
                if granted {
                    self.adbk = adbk
                } else {
                    println(err)
                }//if
            }//ABAddressBookReqeustAccessWithCompletion
        }//case
    }//if
}//viewDidAppear
Chancellorship answered 31/8, 2014 at 2:17 Comment(3)
Good answer. BTW, where you call ABAddressBookCreateWithOptions, though, your err is unmanaged, so unless you call takeRetainedValue() for the err, this will leak. Likewise, where you're setting the properties of the ABRecordRef, (a) I think you can eliminate that UnsafeMutablePointer and just use var error: Unmanaged<CFErrorRef>?; and (b) if any of these lines generate an error, you'll want to likewise want to takeRetainedValue.Magnetize
Thanks - I spent an hour learning what Unmanaged was the other day so I finally understand what you wrote here :) developer.apple.com/library/prerelease/ios/documentation/Swift/…Chancellorship
Figured out how to resolve the Xcode 6.1 error that Rob highlighted months ago. Changing to his suggested syntax, and instead of passing in error as a param, passing in &error, a pointer.Chancellorship
C
9

Add contact with a button click using swift 3

Add this row in project plist

Privacy - Contacts Usage Description

then

import AddressBook
import Contacts

On button click, you add the following

let newContact = CNMutableContact()
newContact.givenName = "Your Name"
newContact.jobTitle = "CTO xyz Company"

let workEmail = CNLabeledValue(label:CNLabelWork, value:"[email protected]" as NSString)
newContact.emailAddresses = [workEmail]
newContact.phoneNumbers = [CNLabeledValue(
    label:CNLabelPhoneNumberiPhone,
    value:CNPhoneNumber(stringValue:"0123456789"))]
do {
    let saveRequest = CNSaveRequest()
    saveRequest.add(newContact, toContainerWithIdentifier: nil)
    try AppDelegate.getAppDelegate().contactStore.execute(saveRequest)
} catch {
    AppDelegate.getAppDelegate().showMessage("Unable to save the new contact.")
}

On app delegate add some custom class

// MARK: Custom functions        
class func getAppDelegate() -> AppDelegate {
    return UIApplication.shared.delegate as! AppDelegate
}

func showMessage(_ message: String) {
    let alertController = UIAlertController(title: "Birthdays", message: message, preferredStyle: UIAlertControllerStyle.alert)

    let dismissAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) { (action) -> Void in
    }

    alertController.addAction(dismissAction)

    let pushedViewControllers = (self.window?.rootViewController as! UINavigationController).viewControllers
    let presentedViewController = pushedViewControllers[pushedViewControllers.count - 1]

    presentedViewController.present(alertController, animated: true, completion: nil)
}

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.main.async(execute: { () -> Void in
                        let message = "\(accessError!.localizedDescription)\n\nPlease allow the app to access your contacts through the Settings."
                        self.showMessage(message)
                    })
                }
            }
        })

    default:
        completionHandler(false)
    }
}

You are done; test the project and check the contact app.

Chemisorb answered 10/2, 2017 at 12:55 Comment(2)
You have to add "let contactStore = CNContactStore()" in the button's viewPragmatic
It's not a question.. you simply forgot to add the line that I wrote in your code example.. :)Pragmatic
J
0

I used the following lines of code

var addressBook : ABAddressBookRef = ABAddressBookCreate()
var contactPerson : ABRecordRef = ABPersonCreate()

ABRecordSetValue(contactPerson, kABPersonFirstNameProperty, txtFirstName.text, nil);
ABRecordSetValue(contactPerson, kABPersonLastNameProperty, txtLastName.text, nil);

But when the record that gets inserted contains "nil"

while reading contacts from address book the following snippet helped

var firstName: NSString! = Unmanaged<CFString>.fromOpaque(ABRecordCopyValue(contactPerson, kABPersonFirstNameProperty).toOpaque()).takeUnretainedValue().__conversion()
Jada answered 4/8, 2014 at 10:46 Comment(1)
1. ABAddressBookCreate() is deprecated. You really should use ABAddressBookCreateWithOptions(). For example, let addressBook:ABAddressBookRef! = ABAddressBookCreateWithOptions(nil, &error).takeRetainedValue(). 2. In the latest betas, the fromOpaque/toOpaque dance is no longer needed. For example, let first = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeRetainedValue() as String.Magnetize

© 2022 - 2024 — McMap. All rights reserved.