Adding Contacts on Apple Platforms without Entitlements

Adding a contact to the user’s address book on Apple platforms using the prescribed method requires jumping through a lot of hoops. You have to:

  • add NSContactsUsageDescription to your info.plist
  • add an entitlement to your app
  • ask the user for authorization (requires an in-app popup)
  • if you want to modify the note field of the contact, you need to get permission from Apple using an online form to be able to add a special com.apple.developer.contacts.notes entitlement to your app; Apple may take up to two weeks to respond just to reject you

For one-off contact additions, there’s a simpler way that requires none of that. The idea is basic: you create a contact, save it in vCard format, and then ask the operating system to open the vCard file in the Contacts app. When the Contacts app opens, it will ask the user if they really want to add the contact. This requires no entitlements (even if you’re using the note field), no authorization, and even works in a sandboxed app.

The Code

I put a Swift macOS example app on GitHub. The code should be easily modifiable to work on iOS. Conveniently, the Contacts framework includes a method for serializing contacts into vCard format. You start by creating a CNMutableContact and filling it with your arbitrary data:

let contact = CNMutableContact()

contact.contactType = .organization
contact.organizationName = "Silly Restaurant"

contact.phoneNumbers = [CNLabeledValue(
        label:CNLabelPhoneNumberMain,
        value:CNPhoneNumber(stringValue:"5555555555"))]

let address = CNMutablePostalAddress()
address.street = "31 Silly Way"
address.city = "Silly Town"
address.state = "Vermont"
address.postalCode = "05401"
address.country = "USA"
contact.postalAddresses = [CNLabeledValue(label:CNLabelWork, value:address)]
contact.urlAddresses = [CNLabeledValue(label: "Apple", value: "https://www.apple.com/")]

Then you can serialize the contact using CNContactVCardSerialization and save it to a temporary file:

let data = try? CNContactVCardSerialization.data(with: [contact])
let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("contact.vcf")
try? data?.write(to: fileURL)

Finally, it’s just a matter of using NSWorkspace to open it in the Contacts app:

if let contactsURL = NSWorkspace.shared.urlForApplication(withBundleIdentifier: "com.apple.AddressBook") {
    NSWorkspace.shared.open([fileURL], withApplicationAt: contactsURL, configuration: NSWorkspace.OpenConfiguration()) {
        (app, error) in
        if let error = error {
            print("Had a problem trying to open the Contacts app.")
            // your error handling here!
        }
    }
}

I hardcoded com.apple.AddressBook as the app to open the vCard here, which is Apple’s Contacts app. You should probably not specify the exact address book app incase the user has a different default.

It works, but you might say, what about that note field? If you add a note property to your CNMutableContact you will notice it is silently dropped when the contact is added to the address book. This has nothing to do with the note special entitlement. It turns out CNContactVCardSerialization does not have support for either images or the note field. You can easily add both of these back. A Stack Overflow post provides some code showing how to do so.

Security Loophole?

When working on a new version of my macOS app Restaurants, I came across the note field entitlement requirement. I submitted a request to Apple using their online form to have access to the entitlement and a week later I was rejected for my request being too vague. Fair enough, it’s their sandbox, and they have the right to reject me for being too vague. But waiting so long to get an answer was frustrating and adding contacts requires a lot of ceremony. Frustrated, I went down the road of this alternative method for adding contacts.

It seems strange to me that you need authorization through Apple’s prescribed method just to add contacts but there is this “side way” using a vCard file that doesn’t require any authorization or entitlements. I’m not saying it’s a security vulnerability. It’s more of a loophole. If Apple really want developers to have to be authorized to do anything with Contacts, this shouldn’t exist.

I filed a security report with Apple thinking maybe they had looked over something so obvious. But I didn’t get a bounty. Instead, they closed it, and marked it as “expected behavior.” I basically expected as much. It seems like too obvious a thing to really be an oversight, but perhaps adding contacts should not require so many hoops to jump through using Apple’s way.

However, a key difference between the two ways of adding contacts, is that an authorized app has access to the contacts database, whereas this method using a temporary file simply opens the Contacts app, which is then in full control of the situation. It’s a lot safer. Any risk is mitigated by the Contacts app. But from a user perspective they look quite similar. In the authorization case, the user gets a pop-up within your app. In the example above, the user gets a pop-up within the Contacts app. The downside, is it does take the user out of your app. But if this is a rarely used feature of your app, maybe it’s worth it, to not have to deal with the frustration!


About Me

I teach Computer Science to college students, develop software, podcast, and write books about programming including the Classic Computer Science Problems series. I'm the publisher of the hyper local newsletter BTV Daily.

You can find me on Twitter and GitHub. Check out my podcasts Kopec Explains Software and Business Books & Co. You can subscribe to my very low volume newsletter to find out about my future book, media, or software projects.

Copyright

©2012-2023 David Kopec. As an Amazon Associate I earn from qualifying purchases.

Based on tdSimple originally by Lasantha Bandara and released under the CC By 3.0.