unable to create a person using VCard representation - iphone

I am developing an app using XCode 4.2 and I am trying to create an ABPerson using initWithVCardRepresentation and/or ABPersonCreatePeopleInSourceWithVCardRepresentation , but I can t find a working example . can someone help?
I get the VCard in an NSString format....
Thanks

This is a full example and it works perfectly, it bases on the latest iOS 8.
First of all you should check authorization status and request access right if not, then save the vcard, let just review the code below:
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized){
NSLog(#"Authorized");
[self addVcardsIntoAddressBook:vcard];
} else{
NSLog(#"Not determined");
ABAddressBookRequestAccessWithCompletion(ABAddressBookCreateWithOptions(NULL, nil), ^(bool granted, CFErrorRef error) {
if (!granted){
NSLog(#"Just denied");
return;
}
NSLog(#"Just authorized");
[self addVcardsIntoAddressBook:vcard];
});
}
This is how to add vcard:
- (void)addVcardsIntoAddressBook:(NSData *)vcard {
CFDataRef vCardData = CFDataCreate(NULL, [vcard bytes], [vcard length]);
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(person);
}
ABAddressBookSave(book, NULL);
}

Here it is Swift version of acoustic's answer;
let vCard : NSData // vcard
let addressBook: ABAddressBook? = ABAddressBookCreateWithOptions(nil, nil)?.takeRetainedValue()
ABAddressBookRequestAccessWithCompletion(addressBook) {
granted, error in
if !granted {
return
}
let vCardData = CFDataCreate(nil, UnsafePointer<UInt8>(vCard.bytes), vCard.length)
let defaultSource = ABAddressBookCopyDefaultSource(addressBook)
let vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource.takeUnretainedValue(), vCardData).takeRetainedValue() as NSArray
for person in vCardPeople {
ABAddressBookAddRecord(addressBook, person, nil)
}
let isSaved = ABAddressBookSave(addressBook, nil)
if isSaved{
//succesfully saved
}
else{
//not saved
}
}

I'm using this code that I found somewhere on a forum:
// Assuming your vCard is stored in vCardString as an NSString
CFDataRef vCardData = (__bridge CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding];
ABAddressBookRef book = ABAddressBookCreate();
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);
CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);
CFIndex index = 0;
ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index);

I am using it and it is working fine with Vcard 2.1 and 3.0
NSString *filename = [[NSBundle mainBundle] pathForResource:#"Contacts" ofType:#"vcf"];
NSLog(#"openning file %#", filename);
NSData *stringData = [NSData dataWithContentsOfFile:filename];
NSString *vCardString = [[NSString alloc] initWithData:stringData encoding:NSUTF8StringEncoding];
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);

Related

Allow App to use contacts pop up not appearing ios7

I am using an application where i want to fetch contacts.The problem is that the app only asks for the first time that app would like to use contacts.Even if i delete the application,clean it and run again,the application is not asking the pop up next time it runs.I debugged the code and found that the permission i gave for the first time is executed.how to solve this.Below is the code i wrote in view did load.
CFErrorRef *error=nil;
ABAddressBookRef addressbook=ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allpeople=ABAddressBookCopyArrayOfAllPeople(addressbook);
CFIndex npeople=ABAddressBookGetPersonCount( addressbook );
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
for ( int i = 0; i < npeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allpeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonLastNameProperty));
NSLog(#"Name:%# %#", firstName, lastName); }
// First time access has been granted, add the contact
} else {
// User denied access
// Display an alert telling user the contact could not be added
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
for ( int i = 0; i < npeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allpeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonLastNameProperty));
NSLog(#"Name:%# %#", firstName, lastName); }
// The user has previously given access, add the contact
}
else {
for ( int i = 0; i < npeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allpeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(ref, kABPersonLastNameProperty));
NSLog(#"Name:%# %#", firstName, lastName); }
// The user has previously denied access
// Send an alert telling user to change privacy setting in settings app
}
Follow the following procedure
Go to Device's Setting->General->Reset->Reset Location & Privacy.
Then it should ask you for permission.

how to edit a phone number values programmatically from address book ios

I'm trying to replace an specific phone number for an specific contact programmatically in iOS, taking the contacts form address book.
I don't know why I can't save the new phone number and refresh the address book to show the change.
I'm doing this:
+(BOOL) changeContactPhoneNumber:(NSString *) phoneSought
forThis:(NSString *) newPhoneNumber{
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef contactSelected;
CFStringRef mobileLabelNumber;
CFErrorRef error = nil;
// Do whatever you want here.
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
for (int i = 0; i < nPeople; i++)
{
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
ABMultiValueRef phones = (ABMultiValueRef)ABRecordCopyValue(ref, kABPersonPhoneProperty);
NSString* mobilePhoneNumber=#"";
if (ABMultiValueGetCount(phones) > 0) {
for (int i=0; i < ABMultiValueGetCount(phones); i++) {
[mobilePhoneNumber release];
mobilePhoneNumber = (NSString*)ABMultiValueCopyValueAtIndex(phones, i);
if([mobilePhoneNumber isEqualToString:phoneSought]){
contactSelected = ref;
mobileLabelNumber = ABMultiValueCopyLabelAtIndex(phones, i);
}
}
}
}
ABMutableMultiValueRef phoneNumberMultiValue = ABMultiValueCreateMutable(kABPersonPhoneProperty);
bool didAddPhone = ABMultiValueAddValueAndLabel(phoneNumberMultiValue ,(__bridge CFTypeRef)newPhoneNumber,mobileLabelNumber, NULL);
if(didAddPhone){
ABRecordSetValue(ABAddressBookGetPersonWithRecordID(addressBook, contactSelected),
kABPersonPhoneProperty,
phoneNumberMultiValue,
nil);
bool bSuccess = ABAddressBookSave(addressBook, &error);
if (!bSuccess) {
NSLog(#"Could not save to address book: %#", error);
} else {
return YES;
}
} else {
NSLog(#"Error editing phone number: %#", error);
error = nil;
}
return NO;
}
You should debug your code and try to figure out whether the format of the phone numbers you are providing to the method are matching or not.
For e.g. when i am logging my contact list phone numbers these are results
Number...555-478-7672
Number...(408) 439-5270
Number...(408) 555-3514
Number...888-555-5512
Number...888-555-1212
Number...555-522-8243
Number...(555) 766-4823
Number...(707) 555-1854
Number...555-610-6679
And i was comparing these number against unformatted number string.
Secondly
ABRecordSetValue(ABAddressBookGetPersonWithRecordID(addressBook, contactSelected),
kABPersonPhoneProperty,
phoneNumberMultiValue,
nil);
Whose actual declaration is
ABRecordSetValue(ABRecordRef record, ABPropertyID property, CFTypeRef value, CFErrorRef* error);
Although ABAddressBookGetPersonWithRecordID returns a ABRecordRef but you already have ABRecordRef contactSelected; so in my view you should use
ABRecordSetValue(contactSelected,kABPersonPhoneProperty,phoneNumberMultiValue,nil);
Please correct me if i am wrong or have misunderstood your code!

Copying contacts from one source to another

I'm trying to copy contacts between my Local contact source and the iCloud contact source and I'm not seeing any results. This code executes without error and seems like it should work, but I don't see the newly created contacts afterward. Anyone see any issues with it?
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef abSourceSource = ABAddressBookGetSourceWithRecordID(addressBook, kABSourceTypeLocal);
ABRecordRef abDestinationSource = ABAddressBookGetSourceWithRecordID(addressBook, kABSourceTypeCardDAV);
CFArrayRef sourceContacts = ABAddressBookCopyArrayOfAllPeopleInSource(addressBook, abSourceSource);
CFArrayRef destinationContacts = ABAddressBookCopyArrayOfAllPeopleInSource(addressBook, abDestinationSource);
ABPersonCreatePeopleInSourceWithVCardRepresentation(abDestinationSource, ABPersonCreateVCardRepresentationWithPeople(sourceContacts));
ABPersonCreatePeopleInSourceWithVCardRepresentation(abSourceSource, ABPersonCreateVCardRepresentationWithPeople(destinationContacts)));
ABAddressBookSave(addressBook, NULL);
There is a more fundamental problem - you are not calling ABAddressBookGetSourceWithRecordID properly. The 2nd parameter it takes is an int that specifies the record id of a particular source in your address book. You are passing it a constant that describes the type of a particular source.
The constant you are passing, kABSourceTypeCardDav is always 4. However, the record id of the iCloud source in a user's address book can be something very different.
What you need to do is enumerate all the sources and test their types, like so:
NSArray *allSources = (NSArray*)ABAddressBookCopyArrayOfAllSources(addressBook);
for (int i = 0; i < allSources.count; i++) {
ABRecordRef src = [allSources objectAtIndex:i];
NSNumber *stObj = (NSNumber*)ABRecordCopyValue(src, kABSourceTypeProperty);
ABSourceType st = (ABSourceType)[stObj intValue];
if (st == kABSourceTypeCardDAV) {
int recordID = ABRecordGetRecordID(src);
break;
}
}
Then you could use recordID as the argument to the first function
I think you forgot to add the records with ABAddressBookAddRecord. Here is my working example:
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef abSource = ABAddressBookGetSourceWithRecordID(addressBook, kABSourceTypeLocal);
NSURL *theURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"some.vcf"];
NSData *vCardData = [NSData dataWithContentsOfURL:theURL];
NSLog(#"data %#", vCardData);
NSArray *createdPeople = (__bridge_transfer NSArray*)ABPersonCreatePeopleInSourceWithVCardRepresentation(abSource, (__bridge CFDataRef)vCardData);
NSLog(#"createdPeople %#", createdPeople);
CFErrorRef error = NULL;
bool ok;
for (id person in createdPeople) {
error = NULL;
ok = ABAddressBookAddRecord(addressBook, (__bridge ABRecordRef)person, &error);
if (!ok) {
NSLog(#"add err %#", error);
break;
}
}
if (ok) {
error = NULL;
BOOL isSaved = ABAddressBookSave(addressBook, &error);
if (isSaved) {
NSLog(#"saved..");
}
if (error != NULL) {
NSLog(#"ABAddressBookSave %#", error);
}
}
CFRelease(addressBook);

Getting iPhone addressbook contents without GUI

I would like to list all phone numbers (or any other field) of people in the addressbook.
I've written the following code:
- (void)addressBookFill{
ABAddressBookRef addressBook = ABAddressBookCreate();
people = (NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
[addressBook release];
}
- (void)printAddressBook{
for(id person in people){
NSLog(#"%#", [person class]);
NSLog(#"\t%#", person );
}
}
When I invoke the printAddressBook method I get this on my console:
2010-07-06 10:34:11.998 app[91420:207] __NSCFType
2010-07-06 10:34:11.999 app[91420:207] <CPRecord: 0x5d56ce0 ABPerson>
And I don't have any idea, how to dereference this ABPerson object, how to get any info from it.
I tried:
firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
but I got some exceptions.
Can anybody tell me how to get some info from these objects?
Read the documentation about the ABPerson class:
http://developer.apple.com/mac/library/documentation/UserExperience/Reference/AddressBook/Classes/ABPerson_Class/Reference/Reference.html
and also the ABRecord class:
http://developer.apple.com/mac/library/documentation/UserExperience/Reference/AddressBook/Classes/ABRecord_Class/Reference/Reference.html#//apple_ref/occ/cl/ABRecord
[ person valueForProperty: #"propName" ]
You can get the available properties with:
[ ABPerson properties ]
[ EDIT ]
On iPhone, you can use the following code to access a value:
NSString * lastName = (NSString *)ABRecordCopyValue( person, kABPersonLastNameProperty );
May be this code will help you for iOS5, please like it
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *arrayOfAllPeople = (__bridge_transfer NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;peopleCounter < [arrayOfAllPeople count]; peopleCounter++){
ABRecordRef thisPerson = (__bridge ABRecordRef) [arrayOfAllPeople objectAtIndex:peopleCounter];
NSString *name = (__bridge_transfer NSString *) ABRecordCopyCompositeName(thisPerson);
NSLog(#"First Name = %#", name);
ABMultiValueRef emails = ABRecordCopyValue(thisPerson, kABPersonEmailProperty);
for (NSUInteger emailCounter = 0; emailCounter < ABMultiValueGetCount(emails); emailCounter++){
/* And then get the email address itself */
NSString *email = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emails, emailCounter);
NSLog(#"Email : %#",email);
}
}
CFRelease(addressBook);
You want get only those contact who has email on my contact so use this code for iOS5
Please like it if it work
First add AddressBook.framework and #import <AddressBook/AddressBook.h>
- (NSArray*)printAddressBook{
NSMutableArray *mutableData = [NSMutableArray new];
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *arrayOfAllPeople = (__bridge_transfer NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;peopleCounter < [arrayOfAllPeople count]; peopleCounter++){
ABRecordRef thisPerson = (__bridge ABRecordRef) [arrayOfAllPeople objectAtIndex:peopleCounter];
NSString *name = (__bridge_transfer NSString *) ABRecordCopyCompositeName(thisPerson);
NSLog(#"First Name = %#", name);
ABMultiValueRef emails = ABRecordCopyValue(thisPerson, kABPersonEmailProperty);
for (NSUInteger emailCounter = 0; emailCounter < ABMultiValueGetCount(emails); emailCounter++){
/* And then get the email address itself */
NSString *email = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emails, emailCounter);
NSLog(#"Email : %#",email);
NSMutableDictionary *personDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:name,#"name",email,#"email", nil];
[mutableData addObject:personDict];
}
}
CFRelease(addressBook);
return [NSArray arrayWithArray:mutableData];
}

Retrieving instant message information from an ABRecordRef

I'm trying to get the instant message account information from existing AddressBook contacts on iOS. I walk through the contacts and I get the contacts which have an instant messaging value, but I can't read the jabber-address.
abArray = (NSArray *)ABAddressBookCopyArrayOfAllPeople(ABAddressBookCreate());
for(int i=0 ; i<[abArray count];i++)
{
ABRecordRef record = [abArray objectAtIndex:i];
ABMutableMultiValueRef multi = ABRecordCopyValue(record, kABPersonInstantMessageProperty);
for(CFIndex x=0;x<ABMultiValueGetCount(multi);x++)
{
CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(multi, x);
CFStringRef jabber = CFDictionaryGetValue(dict, kABPersonInstantMessageServiceJabber);
if(CFDictionaryContainsKey(dict, kABPersonInstantMessageServiceJabber))
{
NSLog(#"yes");
}
else {
NSLog(#"no");
}
// only to make it possible to log to console
NSString *jaab = (NSString *)jabber;
NSLog(#"jabber adress: %#" , jaab);
}
CFRelease(dict);
}
}
What am I doing wrong?
for(int i=0 ; i<[abArray count];i++)
{
ABRecordRef record = [abArray objectAtIndex:i];
ABMutableMultiValueRef multi = ABRecordCopyValue(record, kABPersonInstantMessageProperty);
for(CFIndex x=0;x<ABMultiValueGetCount(multi);x++)
{
CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(multi, x);
CFStringRef jabber;
//Use this piece of code to print the dict to log and check
NSDictionary *nsdict = (NSDictionary *)dict;
NSString *jabberID = [NSString stringWithString:#""];
NSLog(#"Dict: %#", nsdict);
if([[nsdict valueForKey:#"service"] isEqualToString:#"Jabber"]){
jabberID = [nsdict valueForKey:#"username"];
}
//Code to print dict to log ends here. Comment the whole piece if not needed.
if(CFStringCompare((CFStringRef)#"jabber", CFDictionaryGetValue(dict, #"service"), 0))
{
NSLog(#"yes");
jabber = CFDictionaryGetValue(dict, #"username");
// only to make it possible to log to console
NSString *jaab = (NSString *)jabber;
NSLog(#"jabber adress: %#" , jaab);
}
else {
NSLog(#"no");
}
}
//CFRelease(dict);
}