I'm rolling my own PeoplePicker, using the following code to get all my contacts:
ABAddressBookRef ab = ABAddressBookCreate();
ABRecordRef source = ABAddressBookCopyDefaultSource(ab);
NSArray *allContacts = (NSArray *) ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(ab, source, ABPersonGetSortOrdering());
It's worked fine during development, but now we're in beta, and a user complained that when they went to choose a contact in my app, the list they were given to choose from was a small subset of all their contacts in their phone.
We pinned it down to the fact that it was actually just displaying one of their groups.
A while later, I realized you can set your default group in Settings > Mail, Contacts, Calendars > Contacts > Default Group
If a user has a specific group selected, then just that group displays in my app.
I think this is because I'm using ABAddressBookCopyDefaultSource to get all the contacts.
How can I grab all a user's contacts without regard to the default source?
Thanks!
try this,
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
for( int i=0;i< nPeople;i++)
{
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
CFStringRef firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
.....
and so on
}
Related
I have tried many times to differentiate between iPad contacts and other sync contacts from a different server but I haven't been able to find a way to differentiate. How can we get the source? I'd like the account name or user name from where we synced contacts in iPad or iPhone.
CFTypeRef sourceTypeEx; CFArrayRef sources = ABAddressBookCopyArrayOfAllSources(addressBook); CFIndex sourceCount = CFArrayGetCount(sources);
for (CFIndex i = 0 ; i < sourceCount; i++){
ABRecordRef currentSource = CFArrayGetValueAtIndex(sources, i);
sourceTypeEx = ABRecordCopyValue(currentSource, kABSourceTypeExchange);
NSString *obj = [NSString stringWithFormat:#"%#",sourceTypeEx];
}
What I trying to do, is get all contacts and relies if the contact have SocialProfileProperty or not, after get all this contacts that have SocialProfileProperty I will make simple filtration to know if it is Facebook,Twitter,..
Before I post this question I west full day trying to find any solution for this problem ??
But it is allows return 0 ??
ABAddressBookRef addressBook;
CFErrorRef *erer = NULL;
addressBook = ABAddressBookCreateWithOptions(NULL, erer);
CFArrayRef _allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex _nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray *socialArray = [[NSMutableArray alloc] init];
ABMultiValueRef socialProfiles;
for (int i=0;i<_nPeople; i++) {
ABRecordRef _person=CFArrayGetValueAtIndex( _allPeople,i);
NSNumber *recordId = [NSNumber numberWithInteger:ABRecordGetRecordID(_person)];
NSLog(#"%#",recordId);
socialProfiles = ABRecordCopyValue(_person, kABPersonSocialProfileProperty);
if (ABMultiValueGetCount(socialProfiles)>0) {
[socialArray addObject:(__bridge id)(socialProfiles)];
}
}
NSLog(#"%d",socialArray.count);
It is allows return 0 ,until the user marge the Social contacts with native and this does
not happened until he try to delete the Facebook account for example in that case alert appear
and ask if u wanna to marge contacts or not ??? other wise return 0 values :)
So this method will never work until the user marge the FaceBook Contacts with native contacts.
I want to display a ABAddressBook that only shows contacts with an email, so I tried something like this:
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
for( CFIndex emailIndex = 0; emailIndex < nPeople; emailIndex++ ) {
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, emailIndex );
ABMutableMultiValueRef emailRef=ABRecordCopyValue(person, kABPersonEmailProperty);
int emailCount = ABMultiValueGetCount(emailRef);
if(emailCount == 0) {
ABAddressBookRemoveRecord(addressBook, person, NULL);
}
}
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.addressBook = addressBook;
picker.peoplePickerDelegate = self;
[self presentModalViewController:picker animated:YES];
The controller shows, but all the contacts are shown, and if I select the ones without an email, I get a crash. If I called ABAddressBookSave(), then it removes all contacts with an email, but it is a permanent change which even deletes them from the system contacts. What's the right way to do this?
You might need to build an array of contacts that have email, then display it on UITableViewController. This is a way to build such array: https://stackoverflow.com/a/13980023/745862. You can use ABPersonViewController or ABUnknownPersonViewController to display contact details.
Have you considered creating a temporary AddressBook and filling it with those contacts that have email addresses?
You remove all contacts without email address from AddressBook, but didn't save the AddressBook at the end. When the AddressBook is loaded from ABPeoplePickerNavigationController, all previous changes will be lost!
Try this:
if (ABAddressBookHasUnsavedChanges(addressBook))
ABAddressBookSave(addressBook, NULL)
BTW, don't forget to CFRelease() addressBook, allPeople and emailRef.
Did you try to show email values only like this:
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.displayedProperties = #[#(kABPersonEmailProperty)];
Perhaps that already does, what you want? Didn't test it though.
From iOS 8 the ABPeoplePickerNavigationController has a property that resolve your problem:
#property (nonatomic,copy) predicateForEnablingPerson
Code example from Apple doc: https://developer.apple.com/library/prerelease/ios/samplecode/PeoplePicker/Listings/PeoplePicker_AAPL_8or7_EmailPickerViewController_m.html)
ABPeoplePickerNavigationController* abPicker = [ABPeoplePickerNavigationController new];
abPicker.peoplePickerDelegate = self;
//...
if ([abPicker respondsToSelector:#selector(setPredicateForEnablingPerson:)]){
// The people picker will enable selection of persons that have at least one email address.
abPicker.predicateForEnablingPerson = [NSPredicate predicateWithFormat:#"emailAddresses.#count > 0"];
}
Note that from iOS9 the ABPeoplePickerNavigationController is deprecated, you can use the new CNContactPickerViewController in the same way with the property:
#property(nonatomic, copy) NSPredicate *predicateForEnablingContact
From the doc:
You can set a value for this property to determine which contact should become selectable, such as emailAddresses.#count > 0 to enable all the contacts that have an email address to become selectable. If no predicate is set for this property, all contacts become selectable.
I Want to get the contacts on the device without using ABPeoplePickerNavigationController, it is possible in objective-c?
Yes, it's possible. Below there's a simple snippet of code that do the work:
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeopleRef = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, nil, kABPersonSortByFirstName);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
for( int i = 0 ; i < nPeople ; i++ ) {
ABRecordRef ref = CFArrayGetValueAtIndex(allPeopleRef, i );
CFStringRef tmpStringRef = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
NSLog(#"FirstName: %#", (NSString *)tmpStringRef);
CFRelease(tmpStringRef);
}
//clean up memory
CFRelease(allPeopleRef);
CFRelease(addressBook);
For more details, please refer to the Apple Developer Documentation here.
It is. Please refer to the AddresBook programming guide. Direct interaction section.
I am trying to be an ABRecordRef that represents the contact info of a person from addressbook. I built two functions that calls a function to fill in a personal data structure with the info in ABRecordRef.
Here comes the function declarations for the three functions:
+ (NSMutableArray*) getAllContactProfiles{
NSMutableArray *listOfProfile = [[NSMutableArray alloc] init];
//---get the contact information for the api
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeopleInAddressBook = ABAddressBookGetPersonCount(addressBook);
//<- Here I loop through all the contacts and pass the ABRecordRef into the following function
//---release the variables---
CFRelease(addressBook);
CFRelease(people);
[listOfProfile autorelease];
return listOfProfile;
}
The Following Function
+ (MSProfileEntry*) getPersonProfileThroughABRecordRef:(ABRecordRef) person{
MSProfileEntry *mockProfile;
ABRecordID recID=ABRecordGetRecordID(person);
//get the user name
CFStringRef firstName;
firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);//it goes wrong here!
CFStringRef lastName;
lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
//bla bla bla.. the rest of the code
}
Everything goes very well. However, when I try to get the ABRecordRef through ABAddressBookGetPersonWithRecordID like it is in the next method:
The Next Method
+ (MSProfileEntry*) getPersonProfileThroughContactId:(NSInteger*)contactId{
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef person =
ABAddressBookGetPersonWithRecordID(addressBook, (ABRecordID)contactId);
CFRelease(addressBook);
if (person == nil) {
return nil;
}
return [MSContactUtil getPersonProfileThroughABRecordRef:person];
}
The whole app crashes on line:ABRecordCopyValue(person, kABPersonFirstNameProperty);.
The problem now is that ABRecordCopyValue(person, kABPersonFirstNameProperty); works perfectly fine with ABAddressBookCopyArrayOfAllPeople but causes the app to crash with ABAddressBookGetPersonWithRecordID.
Does anyone have any clue how to solve this problem? I really don't want to loop through entire contact base just to look for a contact.
It turned out to be a memory issue. I forgot to retain the "addressBook". By the time I executed the following line:
firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
The "addressBook" had been cleaned out already. Somehow we still need "addressBook" while querying for the detail information in "person".
So, remember to put in the following line, and you will be safe.
CFRetain(addressBook);
Two things:
You pass (NSInteger*)contactId to getPersonProfileThroughContactId and after that you call ABAddressBookGetPersonWithRecordID(addressBook, (ABRecordID)contactId);. Actually you pass an address of the integer that holds the contact id and not the id itself...
You check if (person == nil), BUT person may not be nil - you should compare with NULL. I believe that it IS NULL in your case (because of my previous point).
These 2 things together cause the crash.
Just pass an integer as is - not its address...
EDIT:
Like this:
+ (MSProfileEntry*)getPersonProfileThroughContactId:(NSInteger)contactId