So far I saw methods to get multiple phone numbers if I show a picker so user can select people and then get the phone number.
What I want is retrieving all contacts' numbers.
Is it even possible?
Try this it works for iOS 6 as well as iOS 5.0 or older:
Sample Project Demo
First add the following frameworks in Link Binary With Libraries
AddressBookUI.framework
AddressBook.framework
Then Import
#import <AddressBook/ABAddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
Then use the following code
Requesting permission to access address book
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
__block BOOL accessGranted = NO;
if (&ABAddressBookRequestAccessWithCompletion != NULL) { // We are on iOS 6
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);
}
else { // We are on iOS 5 or Older
accessGranted = YES;
[self getContactsWithAddressBook:addressBook];
}
if (accessGranted) {
[self getContactsWithAddressBook:addressBook];
}
Retrieving contacts from addressbook
// Get the contacts.
- (void)getContactsWithAddressBook:(ABAddressBookRef )addressBook {
contactList = [[NSMutableArray alloc] init];
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
for (int i=0;i < nPeople;i++) {
NSMutableDictionary *dOfPerson=[NSMutableDictionary dictionary];
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
//For username and surname
ABMultiValueRef phones =(__bridge ABMultiValueRef)((__bridge NSString*)ABRecordCopyValue(ref, kABPersonPhoneProperty));
CFStringRef firstName, lastName;
firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
[dOfPerson setObject:[NSString stringWithFormat:#"%# %#", firstName, lastName] forKey:#"name"];
//For Email ids
ABMutableMultiValueRef eMail = ABRecordCopyValue(ref, kABPersonEmailProperty);
if(ABMultiValueGetCount(eMail) > 0) {
[dOfPerson setObject:(__bridge NSString *)ABMultiValueCopyValueAtIndex(eMail, 0) forKey:#"email"];
}
//For Phone number
NSString* mobileLabel;
for(CFIndex j = 0; j < ABMultiValueGetCount(phones); j++) {
mobileLabel = (__bridge NSString*)ABMultiValueCopyLabelAtIndex(phones, j);
if([mobileLabel isEqualToString:(NSString *)kABPersonPhoneMobileLabel])
{
[dOfPerson setObject:(__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, j) forKey:#"phone"];
}
else if ([mobileLabel isEqualToString:(NSString*)kABPersonPhoneIPhoneLabel])
{
[dOfPerson setObject:(__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, j) forKey:#"phone"];
break ;
}
}
[contactList addObject:dOfPerson];
}
NSLog(#"Contacts = %#",contactList);
}
To retrive other information
// All Personal Information Properties
kABPersonFirstNameProperty; // First name - kABStringPropertyType
kABPersonLastNameProperty; // Last name - kABStringPropertyType
kABPersonMiddleNameProperty; // Middle name - kABStringPropertyType
kABPersonPrefixProperty; // Prefix ("Sir" "Duke" "General") - kABStringPropertyType
kABPersonSuffixProperty; // Suffix ("Jr." "Sr." "III") - kABStringPropertyType
kABPersonNicknameProperty; // Nickname - kABStringPropertyType
kABPersonFirstNamePhoneticProperty; // First name Phonetic - kABStringPropertyType
kABPersonLastNamePhoneticProperty; // Last name Phonetic - kABStringPropertyType
kABPersonMiddleNamePhoneticProperty; // Middle name Phonetic - kABStringPropertyType
kABPersonOrganizationProperty; // Company name - kABStringPropertyType
kABPersonJobTitleProperty; // Job Title - kABStringPropertyType
kABPersonDepartmentProperty; // Department name - kABStringPropertyType
kABPersonEmailProperty; // Email(s) - kABMultiStringPropertyType
kABPersonBirthdayProperty; // Birthday associated with this person - kABDateTimePropertyType
kABPersonNoteProperty; // Note - kABStringPropertyType
kABPersonCreationDateProperty; // Creation Date (when first saved)
kABPersonModificationDateProperty; // Last saved date
// All Address Information Properties
kABPersonAddressProperty; // Street address - kABMultiDictionaryPropertyType
kABPersonAddressStreetKey;
kABPersonAddressCityKey;
kABPersonAddressStateKey;
kABPersonAddressZIPKey;
kABPersonAddressCountryKey;
kABPersonAddressCountryCodeKey;
Further Reference Read Apple Docs
UPDATE:
You need to add description about why you need to access the contacts in you Apps-Info.plist
Privacy - Contacts Usage Description
OR
<key>NSContactsUsageDescription</key>
<string>Write the reason why your app needs the contact.</string>
For getting the user image.
UIImage *contactImage;
if(ABPersonHasImageData(ref)){
contactImage = [UIImage imageWithData:(__bridge NSData *)ABPersonCopyImageData(ref)];
}
NOTE:
The AddressBook framework is deprecated in iOS 9 and replaced with the new and improved Contacts Framework
AddressBookUI.framework
AddressBook.framework
These 2 frameworks are deprecated in iOS 9
---> Apple introduced
Contact Framework
ContactUI Framework
Here is uploaded Code using latest frameworks.
Get permission to the address book or notify the user that the need to change the permission in their settings.
CGFloat iOSVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if(iOSVersion >= 6.0) {
// Request authorization to Address Book
addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
//start importing contacts
if(addressBookRef) CFRelease(addressBookRef);
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add the contact
//start importing contacts
if(addressBookRef) CFRelease(addressBookRef);
}
else {
// The user has previously denied access
// Send an alert telling user to change privacy setting in settings app
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Unable to Access" message:#"Grant us access now!" delegate:self cancelButtonTitle:#"Not Now" otherButtonTitles:#"I'll Do It!", nil];
[alert show];
if(addressBookRef) CFRelease(addressBookRef);
}
} else {
addressBookRef = ABAddressBookCreate();
//start importing contacts
if(addressBookRef) CFRelease(addressBookRef);
}
Get the records
CFArrayRef records = ABAddressBookCopyArrayOfAllPeople(addressBook);
NSArray *contacts = (__bridge NSArray*)records;
CFRelease(records);
for(int i = 0; i < contacts.count; i++) {
ABRecordRef record = (__bridge ABRecordRef)[contacts objectAtIndex:i];
}
Get the phone number
ABMultiValueRef phonesRef = ABRecordCopyValue(recordRef, kABPersonPhoneProperty);
if(phonesRef) {
count = ABMultiValueGetCount(phonesRef);
for(int ix = 0; ix < count; ix++){
CFStringRef typeTmp = ABMultiValueCopyLabelAtIndex(phonesRef, ix);
CFStringRef numberRef = ABMultiValueCopyValueAtIndex(phonesRef, ix);
CFStringRef typeRef = ABAddressBookCopyLocalizedLabel(typeTmp);
NSString *phoneNumber = (__bridge NSString *)numberRef;
NSString *phoneType = (__bridge NSString *)typeRef;
if(typeTmp) CFRelease(typeTmp);
if(numberRef) CFRelease(numberRef);
if(typeRef) CFRelease(typeRef);
}
CFRelease(phonesRef);
}
Keep in mind, some people have 20,000 contacts in their phone. If you plan on doing this, you'll probably have to multithread the process.
Sure you can. First you'll need to get the user permission for doing so. If you won't the user will have to manually authorize your app from the settings. There's a great example on how to retrieve all phone numbers, names, addresses etc' here.
Related
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
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!
I'm trying to develop an app, where users can send messages via iMessage. So I'm able to import the contact list from AddressBook, and to send Messages via MessageUI Framework, but I will like to know which of the contacts imported have also iPhone so they can use iMessage capability. Is there any way to find out from the kABPerson...Property?
Here my code:
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
ABAddressBookRef addressBook = ABAddressBookCreate( );
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
CFErrorRef *error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for(int i = 0; i < numberOfPeople; i++) {
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
//Something like this ?
BOOL *doeshaveiPhone = (__bridge BOOL *)(ABRecordCopyValue(person, kABPersonPhoneIPhoneLabel));
NSLog(#"Name:%# Surname: %#", firstName, lastName);
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
for(CFIndex j = 0; j < ABMultiValueGetCount(phones); j++)
{
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(phones, j);
CFStringRef locLabel = ABMultiValueCopyLabelAtIndex(phones, j);
NSString *phoneLabel =(__bridge NSString*) ABAddressBookCopyLocalizedLabel(locLabel);
NSString *phoneNumber = (__bridge NSString *)phoneNumberRef;
CFRelease(phoneNumberRef);
CFRelease(locLabel);
NSLog(#" - %# (%#)", phoneNumber, phoneLabel);
}
}
Your code is the best way to determine if people in the Address Book have iMessage. However, there is a disadvantage: it only works if the user properly sets up their contacts. Too often, fields are improperly set which can make developing applications difficult.
This question has been asked before. Here, the top-voted answer says,
your heurisitic might be ok but it relies on the USER correctly
setting that attribute.
depending on the context it might be good enough / or not .. dont
know.
there is no real way to detect which user really uses ios (no API)
This question already has answers here:
Programmatically get own phone number in iOS
(9 answers)
Closed 8 years ago.
I've been researching how to find the owner phone number of a iOS device, but with no luck. There are post all around showing thirdparty frameworks that allow to do that, but are rejected from Apple.
In my app I'm accessing to the AddressBook Contact and getting all phone contacts, with Name and Phone. In my case (with my iPhone, I didn't test in other iPhones) I can see my own number listed with the rest of contacts. Is there a way to find out/flag or recognize a contact as owner of the iPhone?
Here my Code:
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
ABAddressBookRef addressBook = ABAddressBookCreate( );
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
CFErrorRef *error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for(int i = 0; i < numberOfPeople; i++) {
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSLog(#"Name:%# Surname: %#", firstName, lastName);
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
for(CFIndex j = 0; j < ABMultiValueGetCount(phones); j++)
{
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(phones, j);
CFStringRef locLabel = ABMultiValueCopyLabelAtIndex(phones, j);
NSString *phoneLabel =(__bridge NSString*) ABAddressBookCopyLocalizedLabel(locLabel);
NSString *phoneNumber = (__bridge NSString *)phoneNumberRef;
CFRelease(phoneNumberRef);
CFRelease(locLabel);
NSLog(#" - %# (%#)", phoneNumber, phoneLabel);
}
}
The phone number is not accessible from any Apple public API which means you can't get it.
If you are implementing a dialer application I can't see what you would nee the own phone number for. It's not like you are going to call yourself?
OR
You can get the users phone number from the NSUserDefault:
That is for Jailbroken devices. You should not use these codes if you want your app to be uploaded to AppStore.
[[NSUserDefaults standardUserDefaults] objectForKey:#"SBFormattedPhoneNumber"]
But this will only work if the user has entered his phone number.
There is no way in the official SDK to read anything from the SIM card.
The best thing you can do is already done in this library, give it a try:
ABGetMe
You can toggle to use private API-s or nit with ABGETME_ENABLE_PRIVATE_APIS preprocessor macro.
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...