I'm trying to create an app with a custom interface for searching through one's addressbook. Searching the local addressbook seems easy, but I cannot figure out how to search for a person/record in an Exchange addressbook source (i.e. ABSourceType == kABSourceTypeExchangeGAL). I'm using the following code to find the Exchange addressbook source and query it, but I only ever get back an empty array. I understand asking for the entire list of people in an Exchange addressbook cannot possibly return all entries, but I would expect some subset of that list when I query it. Again, instead I get an empty array.
How do you search for contacts in an Exchange addressbook source?
#define CFNIL(x) if(x){CFRelease(x); x=nil;}
//code
ABAddressBookRef _addressbook = ABAddressBookCreate();
CFArrayRef allSources = ABAddressBookCopyArrayOfAllSources(_addressbook);
ABRecordRef exchangeSource;
for(CFIndex i =0; i<CFArrayGetCount(allSources); i++)
{
ABRecordRef source = (ABRecordRef)CFArrayGetValueAtIndex(allSources, i);
NSNumber *sourceTypeNumber = (NSNumber*)((CFNumberRef)ABRecordCopyValue(source, kABSourceType));
NSString *sourceTypeName = (NSString *)((CFStringRef)ABRecordCopyValue(source, kABSourceNameProperty));
int sourceType = [sourceTypeNumber intValue];
if (sourceType == kABSourceTypeExchangeGAL)
{
exchangeSource = source;
}
[sourceTypeNumber release];
[sourceTypeName release];
}
if(exchangeSource)
{
/*
This finds matches in the local device addressbook
NSArray *people = (NSArray *)ABAddressBookCopyPeopleWithName(_addressbook, CFSTR("joe"));
for(int i=0;i<[people count]; i++)
{
ABRecordRef person = (ABRecordRef)[people objectAtIndex:i];
ABMultiValueRef emails = (ABMultiValueRef)ABRecordCopyValue(person, kABPersonEmailProperty);
NSLog(#"emails: %#",emails);
[((NSArray*)emails) release];
}
[people release];
*/
//this array is always empty
CFArrayRef search = ABAddressBookCopyArrayOfAllPeopleInSource (_addressbook,exchangeSource);
NSLog(#"%#", search);
CFNIL(search);
}
CFNIL(exchangeSource);
CFNIL(_addressbook);
Related
I need to find a contact in AdreesBook in order to add a new social network.
Sometimes I have to find a contact by its phones and emails or by its phones, firstName and lastName, is there any kind of query to get ABRecordRef contact instead of doing whiles?
Many of my users have more than 1000 contacts and I need to update many of them, so it is not efficient if my only solution is to do so many whiles...
Any idea??
Thanks!
Below is method which may help you to get the Contact details using phone number. For that its used kABPersonPhoneProperty, same way you can write another functions for searching email and name:
For email, use a property : kABPersonEmailProperty
For First Name : kABPersonFirstNameProperty
For more details, go through: ABPerson Reference
Hope this helps.
#import <AddressBook/AddressBook.h>
-(NSArray *)contactsContainingPhoneNumber:(NSString *)phoneNumber {
/*
Returns an array of contacts that contain the phone number
*/
// Remove non numeric characters from the phone number
phoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]] componentsJoinedByString:#""];
// Create a new address book object with data from the Address Book database
CFErrorRef error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (!addressBook) {
return [NSArray array];
} else if (error) {
CFRelease(addressBook);
return [NSArray array];
}
// Requests access to address book data from the user
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {});
// Build a predicate that searches for contacts that contain the phone number
NSPredicate *predicate = [NSPredicate predicateWithBlock: ^(id record, NSDictionary *bindings) {
ABMultiValueRef phoneNumbers = ABRecordCopyValue( (__bridge ABRecordRef)record, kABPersonPhoneProperty);
BOOL result = NO;
for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
NSString *contactPhoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i);
contactPhoneNumber = [[contactPhoneNumber componentsSeparatedByCharactersInSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]] componentsJoinedByString:#""];
if ([contactPhoneNumber rangeOfString:phoneNumber].location != NSNotFound) {
result = YES;
break;
}
}
CFRelease(phoneNumbers);
return result;
}];
// Search the users contacts for contacts that contain the phone number
NSArray *allPeople = (NSArray *)CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
NSArray *filteredContacts = [allPeople filteredArrayUsingPredicate:predicate];
CFRelease(addressBook);
return filteredContacts;
}
I have two tableViewControllers. The first one has a list of contacts. The another one shows detailed person's information.
A chunk of code of first tableViewController
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
NSArray *allPeople = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source,kABPersonSortByFirstName);
for ( int i = 0; i < [allPeople count]; i++ )
{
...
contactClass = [[ContactClass alloc] initWithName:name surName:surName manID:[allPeople objectAtIndex:i]];
...
}
A chunck of code of second tableViewController
ABRecordRef person = (__bridge ABRecordRef)contactClass.manID;
BOOL isHasImage = ABPersonHasImageData(person);
Variable isHasImage is always false, even if contact has an avatar. I even checked this on the first tableViewController and if person has an avatar, then it returns true and image.
Does anyone knows why I can't get contacts image?
p.s. contactClass.manID is type of id. It has a correct adress, because ABMultiValueRef multiValue = ABRecordCopyValue((__bridge ABRecordRef)contactClass.manID, kABPersonPhoneProperty); returns correct value in the second tableViewController
I may be too late for a solution for you, but maybe this will help others that are stuck with the same problem.
Looks like ABPersonHasImageData() and ABPersonCopyImageDataWithFormat() don't work as expected on ABRecordRef copies (e.g. an ABContactRef from an array obtained using ABAddressBookCopyArrayOfAllPeople()), at leas on iOS 5.x. You may workaround it like this:
- (UIImage*)imageForContact: (ABRecordRef)contactRef {
UIImage *img = nil;
// can't get image from a ABRecordRef copy
ABRecordID contactID = ABRecordGetRecordID(contactRef);
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef origContactRef = ABAddressBookGetPersonWithRecordID(addressBook, contactID);
if (ABPersonHasImageData(origContactRef)) {
NSData *imgData = (NSData*)ABPersonCopyImageDataWithFormat(origContactRef, kABPersonImageFormatOriginalSize);
img = [UIImage imageWithData: imgData];
[imgData release];
}
CFRelease(addressBook);
return img;
}
Any further update on this ?
I have received complaints for some user not able to see thumbnail for a few contacts. Mostly it works fine, Is there any special case in which thumbnails aren't returned.
I am using the following piece of code:
- (instancetype)initWithABContact:(ABRecordRef)contact {
NSData *iThumbnailData = nil;
if (ABPersonHasImageData(contact)) {
iThumbnailData =
CFBridgingRelease(ABPersonCopyImageDataWithFormat(contact, kABPersonImageFormatThumbnail));
}
}
Have you ever tried to get data fields from the address book and ran into the wonderful world of ABPerson reference only to find it reads like the blueprints to a space rocket?
I've gotten so far but I still need help getting just the Twitter username key & value:
//I tried this but I can't seem to get the if statement to work
ABMutableMultiValueRef socialMulti = ABRecordCopyValue(person, kABPersonSocialProfileProperty);
NSMutableDictionary *mySocialDict = [NSMutableDictionary dictionaryWithCapacity:ABMultiValueGetCount(socialMulti)];
NSLog(#"entering social dict of count %ld", ABMultiValueGetCount(socialMulti));
for (CFIndex i = 0; i < ABMultiValueGetCount(socialMulti); i++) {
CFStringRef socialLabel = ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(socialMulti, i));
CFStringRef social = ABMultiValueCopyValueAtIndex(socialMulti, i);
if ([(__bridge NSString*)socialLabel isEqualToString:#"twitter"]) {
NSLog(#"we got a twitter");
}
[mySocialDict setObject:(__bridge NSString*)social forKey:(__bridge NSString*)socialLabel];
NSLog(#"social is %#",social);
CFRelease(social);
CFRelease(socialLabel);
}
I'm actually just interested in the twitter username. I know I could get it from the dictionary I created but I want to get it directly. I plan to eliminate the NSDictionary step anyway.
Here's an excerpt from my code. Replace your var names as necessary.
ABMultiValueRef socialMulti = ABRecordCopyValue(recordRef, kABPersonSocialProfileProperty);
NSMutableArray* twitterHandlesArray = [[NSMutableArray alloc] initWithCapacity:ABMultiValueGetCount(socialMulti)];
for (CFIndex i = 0; i < ABMultiValueGetCount(socialMulti); i++) {
NSDictionary* social = (__bridge NSDictionary*)ABMultiValueCopyValueAtIndex(socialMulti, i);
if ([social[#"service"] isEqualToString:(__bridge NSString*)kABPersonSocialProfileServiceTwitter]) {
NSString* username = (NSString*)social[#"username"];
NSLog(#"we got a twitter. username is %#", username);
[twitterHandlesArray addObject:[[username conditionedAsTwitterHandle] SHA2Digest]];
}
}
I am using
NSMutableArray *people = [[[(NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook) autorelease] mutableCopy] autorelease];
to access the Addressbook.
Now I want to access a specific Addressbook Group from an Exchange Server.
Is this possible?
You will need to do not something like this.
ABRecordRef exchange = ABAddressBookGetSourceWithRecordID(addressBook, kABSourceTypeExchange);
CFArrayRef groups = ABAddressBookCopyArrayOfAllGroupsInSource(addressBook, exchange);
CFArrayRef officePersonnel;
for (ABRecordRef group in (NSArray *)groups) {
CFStringRef groupName = ABRecordCopyValue(group, kABGroupNameProperty, NULL);
if ( CFStringFind(groupName, CFSTR("Office"), kCFCompareCaseInsensitive) != kCFNotFound ) {
officePersonnel = ABGroupCopyArrayOfAllMembers(group);
}
CFRelease(groupName);
}
CFRelease(groups);
// Use and later release `officePersonnel`
I have a question regarding the AddressBook Framework for iOS. The situation is as follows:
I'm trying recreate the contacts view from the phone application, but I want to show the contact's phone numbers in the same view. So if a contact has more than one number, his name will be in the TableView multiple times, each time with a different number.
I am trying to accomplish that by extracting all the information I need when the view loads and after that, populate the TableView with the appropriate values from an NSArray consisting of NSDictionaries containing the contact's information.
This works great except for one thing... The contact's phonenumbers and labels are read correctly and stored in the dictionary, but when I read them out later, they seem to have vanished.
Here's my code for generating the NSDictionaries, I bet it's some kind of memory management error or something completly stupid. I hope anyone can help me, thanks a lot in advance!
persons = [[NSMutableArray alloc] init];
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
NSArray *people = (NSArray *)ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source, kABPersonSortByLastName);
for (id record in people)
{
ABMultiValueRef numbers = ABRecordCopyValue((ABRecordRef)record, kABPersonPhoneProperty);
for (CFIndex i = 0; i < ABMultiValueGetCount(numbers); ++i) {
CFStringRef label = ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(numbers, i));
CFStringRef number = ABMultiValueCopyValueAtIndex(numbers, i);
CFStringRef firstNameRef = ABRecordCopyValue((ABRecordRef)record, kABPersonFirstNameProperty);
CFStringRef lastNameRef = ABRecordCopyValue((ABRecordRef)record, kABPersonLastNameProperty);
CFDataRef imageDataRef = ABPersonCopyImageDataWithFormat((ABRecordRef)record, kABPersonImageFormatThumbnail);
NSString *firstName = [NSString stringWithFormat:#"%#", firstNameRef];
NSString *lastName = [NSString stringWithFormat:#"%#", lastNameRef];
NSString *pLabel = [[NSString alloc] initWithFormat:#"%#", label];
NSString *pNumber = [NSString stringWithFormat:#"%#", number];
UIImage *image = [UIImage imageWithData:(NSData*)imageDataRef];
NSDictionary *personDict = [NSDictionary dictionaryWithObjectsAndKeys:firstName, #"firstName", lastName, #"lastName", image, #"image", pNumber, #"phoneNumber", pLabel, #"label", nil];
NSLog(#"In %# - %#", pLabel, pNumber);
[persons addObject:personDict];
CFRelease(firstNameRef);
CFRelease(lastNameRef);
//CFRelease(imageDataRef);
CFRelease(label);
CFRelease(number);
}
}
CFRelease(addressBook);
CFRelease(source);
[people release];
Finally could resolve this myself. Apparently I was adding some nil-images to the dictionaries which they couldn't handle.