10

I am designing a QR code reader, and it needs to detect and import contact cards in vCard format (.vcf).

is there a way to add the card data to the system Address Book directly, or do I need to parse the vCard myself and add each field individually?

Carter Allen
  • 1,984
  • 15
  • 22
user1044771
  • 109
  • 1
  • 7

3 Answers3

13

If you're running on iOS 5 or later, this code should do the trick:

#import <AddressBook/AddressBook.h>

// This gets the vCard data from a file in the app bundle called vCard.vcf
//NSURL *vCardURL = [[NSBundle bundleForClass:self.class] URLForResource:@"vCard" withExtension:@"vcf"];
//CFDataRef vCardData = (CFDataRef)[NSData dataWithContentsOfURL:vCardURL];

// This version simply uses a string. I'm assuming you'll get that from somewhere else.
NSString *vCardString = @"vCardDataHere";
// This line converts the string to a CFData object using a simple cast, which doesn't work under ARC
CFDataRef vCardData = (CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding];
// If you're using ARC, use this line instead:
//CFDataRef vCardData = (__bridge CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding];

ABAddressBookRef book = ABAddressBookCreate();
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);
CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);
for (CFIndex index = 0; index < CFArrayGetCount(vCardPeople); index++) {
    ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index);
    ABAddressBookAddRecord(book, person, NULL);
}

CFRelease(vCardPeople);
CFRelease(defaultSource);
ABAddressBookSave(book, NULL);
CFRelease(book);

Make sure to link to the AddressBook framework in your project.

Zhao Xiang
  • 1,625
  • 2
  • 23
  • 40
Carter Allen
  • 1,984
  • 15
  • 22
  • I am in a situation where I will be deciding what the QR code data type will be reading , all I know is that the format of the text will be like this : – user1044771 Nov 14 '11 at 05:48
  • BEGIN:VCARD N;CHARSET=utf-8:;;;; FN;CHARSET=utf-8: ORG;CHARSET=utf-8: TITLE;CHARSET=utf-8: TEL;WORK:<telephone number=""> TEL;WORK;FAX:<fax number=""> EMAIL;INTERNET;WORK;CHARSET=utf-8:<email> ADR;WORK;CHARSET=utf-8:;;<address and="" code="" country="" including="" state="" zip=""> URL;WORK;CHARSET=utf-8:<website> VERSION:2.1 END:VCARD now considering that it will be spread on several lines , can I say that it is an NSString or will the NSSstring will only take the first line of this text ? (I am fairly new to objective C )</website></address></email></fax></telephone> – user1044771 Nov 14 '11 at 05:50
  • NSString can easily store multiple lines of text. – Carter Allen Nov 14 '11 at 21:32
  • I used this code but it is not working First it does not compile this line : CFDataRef vCardData = (CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding]; I have to change it to this : CFDataRef vCardData = (__bridge CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding]; then when it runs it does crashes at this line : for (CFIndex index = 0; index < CFArrayGetCount(vCardPeople); index++) { – user1044771 Nov 16 '11 at 14:37
  • I used this code but it is not working First it does not compile this line : CFDataRef vCardData = (CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding]; I have to change it to this : CFDataRef vCardData = (__bridge CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding]; then when it runs it does crashes at this line : for (CFIndex index = 0; index < CFArrayGetCount(vCardPeople); index++) { it gives the following green error : Tread1:Program Received Signal "EXC_BAD_ACCESS" any reasons ? – user1044771 Nov 16 '11 at 14:43
  • 1
    The bridge code was required because you're using ARC, so that makes sense. Here's the simplest possible problem: are you feeding it a valid vCard string? Or are you just using my placeholder? If you're using the placeholder, that definitely won't work. You need to have a valid vCard string. – Carter Allen Nov 17 '11 at 00:01
  • Hello I do have a VCard String , I changed "__bridge" to "__bridge_retained" and still no luck , it compiles and runs but it does not save in the address book – user1044771 Nov 17 '11 at 13:34
  • I'd like to help more, but it's getting annoying to have to flag all the duplicate questions you're asking. Please stick to this **one** question, and we can try and figure this out. – Carter Allen Nov 17 '11 at 23:33
  • CFRelease(person); is not required and will crash. Ref: https://developer.apple.com/library/mac/#documentation/CoreFOundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-SW1 – Cullen SUN Oct 03 '12 at 18:58
  • how about **before** iOS 5? – tipycalFlow May 17 '13 at 06:30
4

Carter Allen's answer worked for me except that it caused my app to crash on the final statement CFRelease(book);

It turns out that the CFRelease(person); statement should be removed. Doing so stopped my app from crashing. See this answer for explanation https://stackoverflow.com/a/1337086/881103

Also checkout The Create Rule and The Get Rule sections on this page https://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html

Community
  • 1
  • 1
Tom Epps
  • 41
  • 4
1

Contacts is pretty forgiving and will do its best to import your vCard, however it seems that your address is not correct. There should be 7 parameters, separated by semicolons: PO box, Suite #, street address, city, state, ZIP, country. Most people leave off the PO box (and suite #), which is why a typical address has a semicolon (or two) at the beginning. If your address is ill-formed, parameters might end up in the wrong places.

The various fields in a vCard are terminated by a <return>: @"\r"

You don't need CHARSET=utf-8

Cliff Harris
  • 754
  • 2
  • 7
  • 9