ABGroupCreate not working with Exchange - ios

I have a problem when I run this snippet of code on the emulator it works, and I get the id of the group but when I run it on a device the id is set to -1 ... but the error message stays null.
-(NSNumber *)addGroupeToAddressbookWithName:(NSString *)name{
ABAddressBookRef addressBook = ABAddressBookCreate();
CFErrorRef error = NULL;
ABRecordRef group = ABGroupCreate();
ABRecordSetValue(group, kABGroupNameProperty,(__bridge CFStringRef)name, &error);
ABAddressBookAddRecord(addressBook, group, &error);
ABAddressBookSave(addressBook,&error);
NSNumber *gId = [NSNumber numberWithInt:ABRecordGetRecordID(group)];
CFRelease(group);
return gId;
}
I can't figure out what the difference is and how to make it work on a real device.
EDIT: Found that it works if I remove the exchange sync on my phone, but still want it to work while being able to have a exchange account on the phone. So not really solving the problem
EDIT / Answer
Found that it was because exchange don't know about groups, to save a group it is needed to use the right source, also see : Obtaining Specific ABSource from ABAddressBook in iOS 4+
new code:
-(NSNumber *)addGroupeToAddressbookWithName:(NSString *)name{
ABAddressBookRef addressBook = ABAddressBookCreate();
CFErrorRef error = NULL;
CFArrayRef sources = ABAddressBookCopyArrayOfAllSources(addressBook);
CFIndex sourceCount = CFArrayGetCount(sources);
NSNumber *gId = nil;
for (CFIndex i = 0 ; i < sourceCount; i++) {
ABRecordRef currentSource = CFArrayGetValueAtIndex(sources, i);
CFTypeRef sourceType = ABRecordCopyValue(currentSource, kABSourceTypeProperty);
BOOL isMatch = kABSourceTypeLocal == [(__bridge NSNumber *)sourceType intValue];
CFRelease(sourceType);
if (isMatch) {
ABRecordRef group = ABGroupCreateInSource(currentSource);//ABGroupCreate();
ABRecordSetValue(group, kABGroupNameProperty,(__bridge CFStringRef)name, &error);
ABAddressBookAddRecord(addressBook, group, &error);
ABAddressBookSave(addressBook,&error);
gId = [NSNumber numberWithInt:ABRecordGetRecordID(group)];
CFRelease(group);
CFRelease(currentSource);
break;
}
}
CFRelease(sources);
return gId;
}

Found that it was because exchange dont know about groups, to save a group it is needed to use the right source, also see : Obtaining Specific ABSource from ABAddressBook in iOS 4+
new code:
-(NSNumber *)addGroupeToAddressbookWithName:(NSString *)name{
ABAddressBookRef addressBook = ABAddressBookCreate();
CFErrorRef error = NULL;
CFArrayRef sources = ABAddressBookCopyArrayOfAllSources(addressBook);
CFIndex sourceCount = CFArrayGetCount(sources);
NSNumber *gId = nil;
for (CFIndex i = 0 ; i < sourceCount; i++) {
ABRecordRef currentSource = CFArrayGetValueAtIndex(sources, i);
CFTypeRef sourceType = ABRecordCopyValue(currentSource, kABSourceTypeProperty);
BOOL isMatch = kABSourceTypeLocal == [(__bridge NSNumber *)sourceType intValue];
CFRelease(sourceType);
if (isMatch) {
ABRecordRef group = ABGroupCreateInSource(currentSource);//ABGroupCreate();
ABRecordSetValue(group, kABGroupNameProperty,(__bridge CFStringRef)name, &error);
ABAddressBookAddRecord(addressBook, group, &error);
ABAddressBookSave(addressBook,&error);
gId = [NSNumber numberWithInt:ABRecordGetRecordID(group)];
CFRelease(group);
CFRelease(currentSource);
break;
}
}
CFRelease(sources);
return gId;
}

Related

How can i delete contact from main AddressBook when i delete specific group in objective-c?

i want to delete the group on addressBook. i have try this code it is successfully delete the group but on main addressBook contact are not deleted.
CFErrorRef error = NULL;
ABAddressBookRef iPhoneAddressBook = ABAddressBookCreate();
ABRecordRef newGroup;
newGroup = ABAddressBookGetGroupWithRecordID(iPhoneAddressBook,groupId);
ABAddressBookRemoveRecord(iPhoneAddressBook, newGroup, &error);
ABAddressBookSave(iPhoneAddressBook,&error);
my requirement is i have one service to call every time when application is open i have get contact from service in a specific group. so i have delete old group and add new contact which is provide from service but it will twice the contact on main AddressBook because it will only delete group. i want to delete group as well as this group contact are delete on main addressBook both.
Finally my question is... How can i delete the group and group contact from main AddressBook please help me... Thank you in advance..
You can Do this
-(void)RemoveContactGroup:(NSString *)name {
BOOL flag = [self CheckIfGroupExistWithName:name];
if(!flag)
{
return;
}
CFErrorRef error = NULL;
ABAddressBookRef iPhoneAddressBook = ABAddressBookCreate();
ABRecordRef newGroup;
//if Existing Group
newGroup = ABAddressBookGetGroupWithRecordID(iPhoneAddressBook,groupId);
NSArray *member = (__bridge NSArray *)ABGroupCopyArrayOfAllMembers(newGroup);
int nPeople = (int)[member count];
if (nPeople>0)
{
for (int i=0; i<nPeople; i++)
{
ABRecordRef contactPerson = (__bridge ABRecordRef)member[i];
ABAddressBookRemoveRecord(iPhoneAddressBook, (ABRecordRef)contactPerson, &error);
}
}
ABAddressBookSave(iPhoneAddressBook, NULL);
CFRelease(newGroup);
}
First you can check the group are exist or not if exist give the group id
-(BOOL)CheckIfGroupExistWithName:(NSString*)groupName {
hasGroup = NO;
//checks to see if the group is created ad creats group for HiBye 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);
if ([currentGroupName isEqualToString:groupName]){
//!!! important - save groupID for later use
groupId = ABRecordGetRecordID(currentCheckedGroup);
hasGroup=YES;
}
CFRelease(currentCheckedGroup);
}
if (hasGroup==NO){
//id the group does not exist you can create one
}
return hasGroup;
}
Check It.

How to I can edit first name and last on my contact from ABAddressBook

How to I can edit first name and last on my contact from ABAddressBook.
I used this code to find some contacts with name.
+(CFArrayRef)searchContactOnDevice_fromFullName:(NSString *)FullName{
NSString *searchName = [NSString stringWithFormat:#"%#", FullName];
ABAddressBookRef addressbook = ABAddressBookCreate();
CFStringRef nameRef = (__bridge CFStringRef) searchName;
CFArrayRef allSearchRecords = ABAddressBookCopyPeopleWithName(addressbook, nameRef);
return allSearchRecords;
}
If I want to remove some contacts, I can use this code:
+(void)removeContactWithRecordsList:(CFArrayRef) selectedRecords_
{
ABAddressBookRef addressbook = ABAddressBookCreate();
if (selectedRecords_ != NULL)
{
int count = CFArrayGetCount(selectedRecords_);
for (int i = 0; i < count; ++i)
{
ABRecordRef contact = CFArrayGetValueAtIndex(selectedRecords_, i);
ABAddressBookRemoveRecord(addressbook, contact, nil);
}
}
ABAddressBookSave(addressbook, nil);
CFRelease(addressbook);
}
But, I need to edit firstName and lastName for contacts.
How to I can make it.
This code not tested on Xcode....Its an overall idea which should work a/c to me cause I have done this long time ago...Try this...
//Code to edit contact programmatically...
ABAddressBookRef addressbook = ABAddressBookCreate();
if (selectedRecordsCount_ != NULL)
{
ABRecordRef contact = CFArrayGetValueAtIndex(selectedRecordsCount_, index);
contact.firstName = #"My new first name";
contact.lastName= #"My New last name":
ABAddressBookSave(addressbook, nil);
}
CFRelease(addressbook);
Here the whole idea is to fetch a ABRecordRef object (person object) and modify the same... then save the addressbook ....which will save you contact's edited information.
Please let me know if you have anything more to help with this issue

ios edit phone number in contact programmatically [duplicate]

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!

while accessing iCloud contacts in my app results in crash in iOS

I want to access my address book contacts in my app,i am successfully able to retrieve all contacts from my address book but if sync my i-cloud account in my iPad,then my address book get updated from my i-cloud contacts also,and if now i access my contacts it results in crash.
Kindly help me ,i am completely stuck don't know what to do.
I can easily access the address book contacts but once it get synced from i-cloudand after that i fetch the address book,it results in crash and give me bad excess error.
Here is the code that i used to fetch contacts.
+(NSArray *)getAllContacts
{
CFErrorRef *error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}
if (accessGranted) {
#ifdef DEBUG
NSLog(#"Fetching contact info ----> ");
#endif
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source, kABPersonSortByFirstName);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray* items = [NSMutableArray arrayWithCapacity:nPeople];
for (int i = 0; i < nPeople; i++)
{
MContact *contacts = [MContact new];
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
//get First Name and Last Name
contacts.firstName = (__bridge NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty);
contacts.lastName = (__bridge NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty);
if (!contacts.firstName) {
contacts.firstName = #"";
}
if (!contacts.lastName) {
contacts.lastName = #"";
}
NSMutableArray *contactEmails = [NSMutableArray new];
ABMultiValueRef multiEmails = ABRecordCopyValue(person, kABPersonEmailProperty);
for (CFIndex i=0; i<ABMultiValueGetCount(multiEmails); i++) {
CFStringRef contactEmailRef = ABMultiValueCopyValueAtIndex(multiEmails, i);
NSString *contactEmail = (__bridge NSString *)contactEmailRef;
[contactEmails addObject:contactEmail];
// NSLog(#"All emails are:%#", contactEmails);
}
if([contactEmails count]==0){
}
else{
[contacts setemails:contactEmails];
[items addObject:contacts];
}
#ifdef DEBUG
#endif
}
return items;
} else {
#ifdef DEBUG
NSLog(#"Cannot fetch Contacts :( ");
#endif
return NO;
}
}
Did you found exactly where in your code the crash append ? If it is in your "for (int i = 0; i < nPeople; i++)" loop, may be you have an issue on 1 contact only...
PS 1, you should remove line 7 : ....ABAddressBookCreateWithOptions, as you need to check for authorization first....
PS 2, did you really need only contacts from default source ? What about if user have also contact from Lotus Notes or other gmail....
I see one issue but not sure it will solve your crash... You should replace your _bridge by _bridge_transfer :
contacts.firstName = (__bridge_transfer NSString*)ABRecordCopyValue(person,kABPersonFirstNameProperty);
Do the same for lastname....
If it did not solve the crash, I would suggest to try isolate the "person" in your AB witch crash, and try to skip it in your "for loop". This should help us to know if it is only a problem with this person or if it is related to the number of person to load. In my ABLocation App, I know some users have >500 contacts, and they have no PB...

Can't create group in addressbook programmatically on 64bit iPad

I am trying to create a group in my local address book.
I have successfully implemented the code, and it does work well under iOS6 and iOS7 on 32 bit architecture.
However the same code won't do anything on a 64 bit iPad 4. Has anybody experienced something like this?
Here is the code for creating the group:
CFErrorRef error = NULL;
ABRecordRef newGroup = ABGroupCreate();
bool isSucces;
NSLog(#"newGroup: %#", newGroup);
isSucces = ABRecordSetValue(newGroup,
kABGroupNameProperty,
#"KONTAKT",
&error);
if(!isSucces) NSLog(#"error at setting group value");
isSucces = ABAddressBookAddRecord(addressBook, newGroup, &error);
if(!isSucces)NSLog(#"error at adding record to addressbook");
ABAddressBookSave(addressBook, &error);
try this
bool foundIt = NO;
CFArrayRef mygroups = ABAddressBookCopyArrayOfAllGroups(addrBook);
CFIndex numGroups = CFArrayGetCount(mygroups);
for(CFIndex idx=0; idx<numGroups; ++idx) {
ABRecordRef mygroupItem = CFArrayGetValueAtIndex(mygroups, idx);
CFStringRef name = (CFStringRef)ABRecordCopyValue(mygroupItem, kABGroupNameProperty);
bool isMatch = [newName isEqualToString:(NSString *)name];
CFRelease(name);
if(isMatch) {
groupNum = [NSNumber numberWithInt:ABRecordGetRecordID(mygroupItem)];
[self setObject:groupNum forKey:kGroupID];
foundIt = YES;
break;
}
}
CFRelease(mygroups);
if(!foundIt) {
ABRecordRef mygroupItem = ABGroupCreate();
ABRecordSetValue(mygroupItem, kABGroupNameProperty, (CFStringRef *)newName, &error);
if(!error) {
ABAddressBookAddRecord (addrBook, mygroupItem, &error);
ABAddressBookSave(addrBook, &error);
groupNum = [NSNumber numberWithInt:ABRecordGetRecordID(groupItem)];
[self setObject:groupNum forKey:kGroupID];
}
CFRelease(mygroupItem);
}

Resources