Retrieve All Contacts Phone Numbers in iOS

Retrieve all contacts phone numbers in iOS

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 
#import

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

NSContactsUsageDescription
Write the reason why your app needs the contact.

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

get all contact phone numbers with ContactsUI in swift

Instead of having it as a String, use an array of strings.

class ContactsModel : NSObject {
let givenName: String
let familyName: String
let phoneNumber: [String]
let emailAddress: String
var identifier: String
var image: UIImage

init(givenName:String, familyName:String, phoneNumber:[String], emailAddress:String, identifier:String, image:UIImage) {
self.givenName = givenName
self.familyName = familyName
self.phoneNumber = phoneNumber
self.emailAddress = emailAddress
self.identifier = identifier
self.image = image
}

class func generateModelArray() -> [ContactsModel]{
let contactStore = CNContactStore()
var contactsData = [ContactsModel]()
let key = [CNContactGivenNameKey,CNContactFamilyNameKey,CNContactImageDataKey,CNContactThumbnailImageDataKey,CNContactPhoneNumbersKey,CNContactEmailAddressesKey] as [CNKeyDescriptor]
let request = CNContactFetchRequest(keysToFetch: key)
try? contactStore.enumerateContacts(with: request, usingBlock: { (contact, stoppingPointer) in
let givenName = contact.givenName
let familyName = contact.familyName
let emailAddress = contact.emailAddresses.first?.value ?? ""
let phoneNumber: [String] = contact.phoneNumbers.map{ $0.value.stringValue }
let identifier = contact.identifier
var image = UIImage()
if contact.thumbnailImageData != nil{
image = UIImage(data: contact.thumbnailImageData!)!

}else if contact.thumbnailImageData == nil ,givenName.isEmpty || familyName.isEmpty{
image = UIImage(named: "usertwo")!
}
contactsData.append(ContactsModel(givenName: givenName, familyName: familyName, phoneNumber: phoneNumber, emailAddress: emailAddress as String, identifier: identifier, image: image))
})
return contactsData
}
}

iOS Contacts How to Fetch contact by phone Number

The problem with your implementation is that you access the address book in every search you are making.

If instead you will hold in-memory the address book content after the first access you will not reach this high CPU usage.

  1. First hold a lazy var in your controller that will hold the address book content:

    lazy var contacts: [CNContact] = {
    let contactStore = CNContactStore()
    let keysToFetch = [
    CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName),
    CNContactEmailAddressesKey,
    CNContactPhoneNumbersKey,
    CNContactImageDataAvailableKey,
    CNContactThumbnailImageDataKey]

    // Get all the containers
    var allContainers: [CNContainer] = []
    do {
    allContainers = try contactStore.containersMatchingPredicate(nil)
    } catch {
    print("Error fetching containers")
    }

    var results: [CNContact] = []

    // Iterate all containers and append their contacts to our results array
    for container in allContainers {
    let fetchPredicate = CNContact.predicateForContactsInContainerWithIdentifier(container.identifier)

    do {
    let containerResults = try contactStore.unifiedContactsMatchingPredicate(fetchPredicate, keysToFetch: keysToFetch)
    results.appendContentsOf(containerResults)
    } catch {
    print("Error fetching results for container")
    }
    }

    return results
    }()

    1. Iterate through the in-memory array when you are looking for a contact with a specific phone number:

    .

       func searchForContactUsingPhoneNumber(phoneNumber: String) -> [CNContact] {
    var result: [CNContact] = []

    for contact in self.contacts {
    if (!contact.phoneNumbers.isEmpty) {
    let phoneNumberToCompareAgainst = phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
    for phoneNumber in contact.phoneNumbers {
    if let phoneNumberStruct = phoneNumber.value as? CNPhoneNumber {
    let phoneNumberString = phoneNumberStruct.stringValue
    let phoneNumberToCompare = phoneNumberString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
    if phoneNumberToCompare == phoneNumberToCompareAgainst {
    result.append(contact)
    }
    }
    }
    }
    }

    return result
    }

I tested it with a very big address book, it works smoothly.

Here is the entire view controller patched together for reference.

import UIKit
import Contacts

class ViewController: UIViewController {

lazy var contacts: [CNContact] = {
let contactStore = CNContactStore()
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName),
CNContactEmailAddressesKey,
CNContactPhoneNumbersKey,
CNContactImageDataAvailableKey,
CNContactThumbnailImageDataKey]

// Get all the containers
var allContainers: [CNContainer] = []
do {
allContainers = try contactStore.containersMatchingPredicate(nil)
} catch {
print("Error fetching containers")
}

var results: [CNContact] = []

// Iterate all containers and append their contacts to our results array
for container in allContainers {
let fetchPredicate = CNContact.predicateForContactsInContainerWithIdentifier(container.identifier)

do {
let containerResults = try contactStore.unifiedContactsMatchingPredicate(fetchPredicate, keysToFetch: keysToFetch)
results.appendContentsOf(containerResults)
} catch {
print("Error fetching results for container")
}
}

return results
}()

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

let contact = searchForContactUsingPhoneNumber("(555)564-8583")
print(contact)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

func searchForContactUsingPhoneNumber(phoneNumber: String) -> [CNContact] {

var result: [CNContact] = []

for contact in self.contacts {
if (!contact.phoneNumbers.isEmpty) {
let phoneNumberToCompareAgainst = phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
for phoneNumber in contact.phoneNumbers {
if let phoneNumberStruct = phoneNumber.value as? CNPhoneNumber {
let phoneNumberString = phoneNumberStruct.stringValue
let phoneNumberToCompare = phoneNumberString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
if phoneNumberToCompare == phoneNumberToCompareAgainst {
result.append(contact)
}
}
}
}
}

return result
}
}

I used flohei's answer for the lazy var part.

Get a list of all contacts on iOS

Perhaps ABPerson function ABAddressBookCopyArrayOfAllPeople might do?

Example:

ABAddressBookRef addressBook = ABAddressBookCreate( );
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );

for ( int i = 0; i < nPeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allPeople, i );
...
}

How can I get all my contacts phone numbers into an array?

You can attempt to do this by using the Contacts Framework.

You'll need to ask for the user's permission before accessing this information.

Fetching all contacts in ios Swift?

Many answers to Contact Framework questions suggest iterating over various containers (accounts). However, Apple's documentation describes a "Unified Contact" as

Contacts in different accounts that represent the same person may be automatically linked together. Linked contacts are displayed in OS X and iOS apps as unified contacts. A unified contact is an in-memory, temporary view of the set of linked contacts that are merged into one contact.

By default the Contacts framework returns unified contacts. Each fetched unified contact (CNContact) object has its own unique identifier that is different from any individual contact’s identifier in the set of linked contacts. A refetch of a unified contact should be done with its identifier.
Source

So simplest way to fetch a list of (partial, based on keys) contacts in a single array, would be the following:

      var contacts = [CNContact]()
let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)]
let request = CNContactFetchRequest(keysToFetch: keys)

let contactStore = CNContactStore()
do {
try contactStore.enumerateContacts(with: request) {
(contact, stop) in
// Array containing all unified contacts from everywhere
contacts.append(contact)
}
}
catch {
print("unable to fetch contacts")
}

How to get My Number from AddressBook framework ?

This is not allowed. There is no public API to get user's phone number.
There are few open question on SO that cover this theme. For example this.

How do I get only the first phone number from every contact on a device?

The problem with your approach is that you are creating a global array of phone numbers and then adding ALL of the phone numbers to this. Instead you only want to add the FIRST phone number.

I would modify the following code:

for (CNLabeledValue *label in contact.phoneNumbers) {
phone = [label.value stringValue];
if ([phone length] > 0) {
[self.phoneNumberArray addObject:phone];
break;
}
}

if (contact.phoneNumbers.count == 0) {
[self.phoneNumberArray addObject: @""];
}

The logic has now changed:

  1. We add each user to an array
  2. In the phone number array we only add their corresponding first number
  3. Now our two arrays are directly linked. It is worth checking at the end that the phone number array always has the same count as the user array
  4. We call break to exit

With this new functionality - and touched on in 3. We need to add some more checking. For example what if a user doesn't have any phone numbers - in this case we need to add a blank phone number to ensure the numbers stay appropriate to the contacts.

if ([label isEqualTo: contact.phoneNumbers.lastValue]) {
[self.phoneNumberArray addObject: @""];
}

Also above is another potential check - if we loop through all the phone numbers and don't add a number then we add a blank number anyway. You need to look at your data and see the different scenarios you might encounter.

Alternative solution:

The above solution is a quick fix to get your code working - personally though I am not a big fan of that approach - what if you want to use more than one number for each? What if you want to click a user to view all numbers? When architecting code it is worth thinking about ways to ensure that it can be refactored more easily later.

Not going to different (Coredata and objects etc) I would prefer to have an array of dictionaries for each contact. This array would store their details (name, phone number etc) and would be easily accessible in each cell.

[addressBook enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {

NSMutableArray * phoneNumbersTemp = [NSMutableArray new];

for (CNLabeledValue *label in contact.phoneNumbers) {
phone = [label.value stringValue];
if ([phone length] > 0) {
[phoneNumbersTemp addObject:phone];
}
}

NSDictionary * contactDict = @{name: contact.name,
phoneNumbers: phoneNumbersTemp}

[self.contactsArray addObject:contactDict];
}];

Note: This is sudo code and has not been tested - it is to highlight the method

This kind of code will then allow you to access the first phone number in each cell (just get the contact phone dictionary for each user and get the first entry) but also allow you to build a contact object for advanced functionality.

How to fetch only mobile numbers in swift using CNContacts?

Check if the number's label is mobile like this:

var mobiles = [CNPhoneNumber]()

for num in contact.phoneNumbers {
let numVal = num.value as! CNPhoneNumber
if num.label == CNLabelPhoneNumberMobile {
mobiles.append(numVal)
}
}

Then you have an array of mobile phone numbers for that person.



Related Topics



Leave a reply



Submit