Copying contacts from one source to another - iphone

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);

Related

how to add a contacts to a particular group ? ios

Fetching contacts and creating group and pushing the contact inot group using group id is getting failed in ios
i check the Group exists already or not and create group if no available
-(void) CheckIfGroupExistWithName:(NSString*)groupName {
BOOL hasGroup = NO;
//checks to see if the group is created ad creats group for contacts
// ABAddressBookRef addressBook = ABAddressBookCreate();
CFIndex groupCount = ABAddressBookGetGroupCount(addressBook);
CFArrayRef groupLists= ABAddressBookCopyArrayOfAllGroups(addressBook);
for (int i=0; i<groupCount; i++) {
ABRecordRef currentCheckedGroup = CFArrayGetValueAtIndex(groupLists, i);
NSString *currentGroupName = (__bridge NSString *)ABRecordCopyCompositeName(currentCheckedGroup);
NSLog(#"GroupName= %#",groupName);
if ([currentGroupName isEqualToString:groupName]){
//!!! important - save groupID for later use
groupId = ABRecordGetRecordID(currentCheckedGroup);
NSLog(#"group id = %i",groupId);
hasGroup=YES;
}
}
if (hasGroup==NO){
//id the group does not exist you can create one
[self createNewGroup:groupName];
}
//CFRelease(currentCheckedGroup);
CFRelease(groupLists);
//CFRelease(addressBook);
}
get the contact details and tries to save by this way
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
NSString *name = (__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
contactNameText.text=name;
ABMultiValueRef phones = (ABMultiValueRef)ABRecordCopyValue(person, kABPersonPhoneProperty);
NSString* mobile=#"";
mobile = (__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, 0);
contactNoText.text=mobile;
CFErrorRef error=NULL;
addressBook = ABAddressBookCreate();
ABRecordRef ICEBUZZGroup = ABAddressBookGetGroupWithRecordID(addressBook, groupId);
BOOL didAdd = ABGroupAddMember(ICEBUZZGroup,person,&error);
if (!didAdd) {
}
BOOL didSave = ABAddressBookSave(addressBook, &error);
if (!didSave) {
}
PLs help
Thank in advance

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!

unable to create a person using VCard representation

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);

iPhone address book problem

I'm having a bit of an issue with using the address book to get the names of the contacts from the device into my own contacts view within my application.
The code I have works fine on the emulator but I when tested on an iPhone 4 it will crash, the application seems to work fine if there are two or less contacts but 3 or more and the application crashes.
Here is the code I am using to get the names of contacts into an array.
ABAddressBookRef addressBook;
bool wantToSaveChanges = YES;
bool didSave;
CFErrorRef error = NULL;
addressBook = ABAddressBookCreate();
listOfContacts = [[NSMutableArray alloc]init];
int i;
int len = (int) ABAddressBookGetPersonCount(addressBook);
for(i = 1; i< (len+1); i++){
ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, (ABRecordID) i);
NSString* name = (NSString *)ABRecordCopyCompositeName(person);
ABMultiValueRef number = (NSString *)ABRecordCopyValue(person,kABPersonPhoneProperty);
NSString *mobileNum = (NSString *)ABMultiValueCopyValueAtIndex(number, 0 );
NSLog(#"Name = %#", name);
NSLog(#"Number = %#", mobileNum);
[listOfContacts addObject:name];
[name release];
[mobileNum release];
}
if(ABAddressBookHasUnsavedChanges(addressBook)){
if(wantToSaveChanges){
didSave = ABAddressBookSave(addressBook, &error);
if(!didSave){
//Error
}
}
else{
ABAddressBookRevert(addressBook);
}
}
When it crashes this is the line that gets highlighted in Xcode:
NSString* name = (NSString *)ABRecordCopyCompositeName(person);
And the error states:
Thread 1: Program received signal: "EXC_BAD_ACCESS"
Can anyone see what the problem might be? I dont understand why it would work on the emulator but not on the device? And also why it works for up to two contacts but not 3 or more??
Just a guess:
ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, (ABRecordID) i);
This line looks fishy for me. I doubt that the record IDs are numbered from 1 to whatever. Especially if you have deleted an entry.
This would explain why it works on the simulator, I guess you just added some test contacts and never deleted one.
Here is how I solved it:
(Note how I make sure to call only active records, also I created a customized Contact class)
This code takes care of edge case like: email/phone doesn't exist, or exists more than once...
+(NSArray *)getAddressBook{
ABAddressBookRef addressBook;
bool wantToSaveChanges = YES;
bool didSave;
CFErrorRef error = NULL;
addressBook = ABAddressBookCreate();
NSMutableArray *listOfContacts = [[NSMutableArray alloc]init];
CFArrayRef array=ABAddressBookCopyArrayOfAllPeople(addressBook);
int len=CFArrayGetCount(array);
for (int i = 0; i<len; i++){
ABRecordRef person = CFArrayGetValueAtIndex(array, i);
if (ABRecordGetRecordType(person)==kABPersonType){
NSString *firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
ABMultiValueRef emails = (ABMultiValueRef)ABRecordCopyValue(person,kABPersonEmailProperty);
ABMultiValueRef numbers = (ABMultiValueRef)ABRecordCopyValue(person,kABPersonPhoneProperty);
int sumEmails=ABMultiValueGetCount(emails);
int sumNumbers=ABMultiValueGetCount(numbers);
for (int j=0; j<(sumNumbers>sumEmails?sumNumbers:sumEmails); j++) {
ACL_AB_Contact *contact=[[ACL_AB_Contact alloc]initWithFirstName:firstName LastName:lastName];
if (j<sumEmails){
contact.emailAddress=(NSString *)ABMultiValueCopyValueAtIndex(emails,j);
}
if (j<sumNumbers){
contact.phoneNumber=(NSString *)ABMultiValueCopyValueAtIndex(numbers,j);
}
[contact logContact];
[listOfContacts addObject:contact];
[contact release];
}
}
}
if(ABAddressBookHasUnsavedChanges(addressBook)){
if(wantToSaveChanges){
didSave = ABAddressBookSave(addressBook, &error);
if(!didSave){
//Error
}
}
else{
ABAddressBookRevert(addressBook);
}
}
return [listOfContacts autorelease];
}
The record IDs are dynamic. It means that if you add 2 contacts and then remove the first, you will have only a contact with id "2". So I wouln't use a for statement to get through the contacts. Follow the Address Book Programming Guide

How to delete a contact from address book in iPhone using objective-c?

I want to delete a contact from the address book in iPhone how can we do that ?
Thanks
ABAddressBookRemoveRecord
http://developer.apple.com/iphone/library/documentation/AddressBook/Reference/ABAddressBookRef_iPhoneOS/Reference/reference.html#//apple_ref/c/func/ABAddressBookRemoveRecord
Here is a sample code to do the same:
- (void)delAllContacts {
ABAddressBookRef addressBook = CFBridgingRetain((__bridge id)(ABAddressBookCreateWithOptions(NULL, NULL)));
int count = ABAddressBookGetPersonCount(addressBook);
if(count==0 && addressBook!=NULL) { //If there are no contacts, don't delete
CFRelease(addressBook);
return;
}
//Get all contacts and store it in a CFArrayRef
CFArrayRef theArray = ABAddressBookCopyArrayOfAllPeople(addressBook);
for(CFIndex i=0;i<count;i++) {
ABRecordRef person = CFArrayGetValueAtIndex(theArray, i); //Get the ABRecord
BOOL result = ABAddressBookRemoveRecord (addressBook,person,NULL); //remove it
if(result==YES) { //if successful removal
BOOL save = ABAddressBookSave(addressBook, NULL); //save address book state
if(save==YES && person!=NULL) {
CFRelease(person);
} else {
NSLog(#"Couldn't save, breaking out");
break;
}
} else {
NSLog(#"Couldn't delete, breaking out");
break;
}
}
if(addressBook!=NULL) {
CFRelease(addressBook);
}
}
+(BOOL)removedRecordFromAddressBookWithFirstValue:(NSString *)fullName{
BOOL recordRemoved=NO;
CFErrorRef err;
ABAddressBookRef addressBook=
ABAddressBookCreateWithOptions(NULL,&err);
CFArrayRef people=ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople=ABAddressBookGetPersonCount(addressBook);
NSString *currRecordFullName=[[NSString alloc] init];
/*Invariant: No record with the name fullName has been
found so far.*/
for(int i=0;i<nPeople;i++){
ABRecordRef ref=CFArrayGetValueAtIndex(people,i);
CFErrorRef error=NULL;
currRecordFullName=nil;
currRecordFullName=[[NSString alloc] init];
currRecordFullName=
(__bridge NSString *)ABRecordCopyCompositeName(ref);
if([currRecordFullName isEqualToString:fullName]){
/*The record to be deleted has been found.*/
ABAddressBookRemoveRecord(addressBook,ref,&error);
ABAddressBookSave(addressBook,&error);
CFRelease(ref);
CFRelease(addressBook);
if(error!=NULL){
CFStringRef errorDesc=CFErrorCopyDescription(error);
NSLog(#"Failed to remove record: %#",errorDesc);
CFRelease(errorDesc);
}else{
NSLog(#"Record removed");
recordRemoved=YES;
}
break;
}else{;}
}
return recordRemoved;
}