I followed Apple's tutorial on obtaining a contact's phone number and it works great but it only detects phone numbers with the "Home" label. Here is my code:
- (void)displayPerson:(ABRecordRef)person {
NSString* phone = nil;
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person,
kABPersonPhoneProperty);
if (ABMultiValueGetCount(phoneNumbers) > 0) {
phone = (__bridge_transfer NSString*)
ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
} else {
phone = #"[None]";
}
self.contactNumber.text = phone;
CFRelease(phoneNumbers); }
Anyone know why it is doing this?
That's because this line
ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
tells it to get the first phone number, i.e "Home" number.
See this post:
Access to people info in iPhone address book
Related
I have a requirement to determine if a contact that is saved in the address book has multiple mobile numbers.
I have the record ID of a Contact and I need to check if that contact has multiple mobile numbers.
Is this possible?
Got the Answer!!! I have written a method to get the total count of mobile numbers for a contact
-(NSInteger)getCountOfTotalMobileNumbersForContact:(ContactData *)contactData{
NSInteger totalCountOfMobileNumbers = 0;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
ABRecordRef contact = ABAddressBookGetPersonWithRecordID(addressBook, (int)contactData.mRecordID);
if(contact != nil)
{
self.phoneNumbers = ABRecordCopyValue(contact, kABPersonPhoneProperty);
NSString *lFirstName = (__bridge_transfer NSString*)ABRecordCopyValue(contact, kABPersonFirstNameProperty);
NSString *lLastName = (__bridge_transfer NSString*)ABRecordCopyValue(contact, kABPersonLastNameProperty);
NSString *fullName = lFirstName;
if (lLastName.length) {
fullName = [[lFirstName stringByAppendingString:#" "] stringByAppendingString:lLastName];
}
totalCountOfMobileNumbers = ABMultiValueGetCount(self.phoneNumbers);
}
return totalCountOfMobileNumbers;
}
we're having an issue where incorrect selections are being returned from the contacts database on some devices. Is there a way to modify the below code to only return the selected item from a persons contact information? In this case we want the exact selected email address from a persons contact to be returned.
Thanks in advance for the help! Heres the code...
-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property: (ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
NSMutableDictionary *contactInfoDict = [[NSMutableDictionary alloc]
initWithObjects:#[#"", #"", #""]
forKeys:#[#"first_name", #"last_name", #"email"]];
// Use a general Core Foundation object.
CFTypeRef generalCFObject = ABRecordCopyValue(person, kABPersonFirstNameProperty);
// Get the first name.
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"first_name"];
CFRelease(generalCFObject);
}
// Get the last name.
generalCFObject = ABRecordCopyValue(person, kABPersonLastNameProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"last_name"];
CFRelease(generalCFObject);
}
// Load selected email addre'
if (property == kABPersonEmailProperty) {
ABMultiValueRef emails = ABRecordCopyValue(person, property);
CFIndex ix = ABMultiValueGetIndexForIdentifier(emails, identifier);
CFStringRef email = ABMultiValueCopyValueAtIndex(emails, ix);
emailAccount = (__bridge NSString *)(email);
[contactInfoDict setObject:emailAccount forKey:#"email"];
if (email) CFRelease(email);
if (emails) CFRelease(emails);
}
// init array
if (_arrContactsData == nil) {
_arrContactsData = [[NSMutableArray alloc] init];
}
// Send contact to server
[self sendContact:contactInfoDict];
// Set data for contacts
[_arrContactsData addObject:contactInfoDict];
// Reload the table view data.
[self.myTable reloadData];
// Dismiss the address book view controller.
[_addressBookController dismissViewControllerAnimated:YES completion:nil];
return NO;
}
Your code is correct.
Are the users experiencing the problem using iOS 8, by any chance? I discovered a bug in iOS 8 beta 6. If you:
Create a contact with email addresses:
Edit the contact, adding an email address and deleting one of the other email addresses:
(Note, don't just edit one of the email addresses, but rather add a new email address and remove and old one.)
In iOS 7, if you iterate through the email addresses, you will see:
{
identifier = 1;
index = 0;
label = "_$!<Work>!$_";
value = "work#gmail.com";
},
{
identifier = 2;
index = 1;
label = "_$!<Other>!$_";
value = "other#gmail.com";
}
This is correct. (When the contact was first created, the identifiers were 0 and 1, when I add the "other" email address, that gets an identifier of 2; when I delete the "home" email address, the email address with the identifier of 0 is deleted, but the other identifiers are correctly unaltered.) Thus, if you tap on the "work" email address, shouldContinueAfterSelectingPerson will return an ABMultiValueIdentifier of 1, which translates to a CFIndex of 0, which will correctly return the "work" email address.
In iOS 8 Beta 6, however, the ABMultiValueRef is incorrectly represented as:
{
identifier = 0;
index = 0;
label = "_$!<Work>!$_";
value = "work#gmail.com";
},
{
identifier = 1;
index = 1;
label = "_$!<Other>!$_";
value = "other#gmail.com";
}
These identifiers are incorrect. Worse, if you tap on the "work" email address, didSelectPerson (which replaces the deprecated shouldContinueAfterSelectingPerson) will return a ABMultiValueIdentifier of 1 (which is what it should have been ... it looks like this delegate method returns the appropriate identifier, but that the ABRecordRef for this edited record has the wrong identifiers ... not sure how they did that!), which translates to a CFIndex of 1, which will correctly return the "other" email address (!).
Worse, if you tapped on the "other" email address, didSelectPerson will return a ABMultiValueIdentifier of 2 (which is what it should have been), but if you try to retrieve the CFIndex, you'll get -1 (because no such ABMultiValueIdentifier exists) and because the app doesn't check for this, any attempt to use ABMultiValueCopyValueAtIndex with this invalid index will result in crash!
This bug seems to be fixed in the iOS8 GM seed, so it appears to be a beta problem only.
I want to check if a contact in my user's addressbook a phone number has. If he does, I want to display that name in an UITableView
I've tried to check for phoneNumbers != nil, but that doesn't work. This is my entire code:
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
if(phoneNumbers != nil){
[_numbers addObject:[NSString stringWithFormat:#"%#", phoneNumbers]];
}
Use ABMultiValueGetCount to check if phoneNumbers has any values in it.
example based on question:
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
if(ABMultiValueGetCount(phoneNumbers)){
[_numbers addObject:[NSString stringWithFormat:#"%#", phoneNumbers]];
}
In my peoplePickerNavigationController:shouldContinueAfterSelectingPerson I'm able to read a bunch of the iOS Contacts info from the chosen contact into my app.
The one item I can't figure out how to read is the Facebook (and other social) address info. Here's what I've got and I know it's not quite right. The problem has something to do with the label I think:
ABMultiValueRef socialRef = ABRecordCopyValue(person, kABPersonSocialProfileProperty);
for (int i = 0; i < ABMultiValueGetCount(socialRef); i++) {
CFStringRef currentSocialLabel = ABMultiValueCopyLabelAtIndex(socialRef, i);
CFStringRef currentSocialValue = ABMultiValueCopyValueAtIndex(socialRef, i);
if (CFStringCompare(currentSocialLabel, kABPersonSocialProfileServiceFacebook, 0) == kCFCompareEqualTo) {
[theContactInfoDictionary setObject:(__bridge NSString *)currentSocialValue forKey:#"theFacebook"];
}
CFRelease(currentSocialLabel);
CFRelease(currentSocialValue);
}
CFRelease(socialRef);
Please point me in the right direction.
Furthermore, I also need to check if there is a custom social entry for "Google+" (my app can create these entries in another place) and if there is, I want to import that value as well. How do I go about doing this?
Thanks!
sigh
And I figured it out. Here's what I did:
ABMultiValueRef socialRef = ABRecordCopyValue(person, kABPersonSocialProfileProperty);
for (int i = 0; i < ABMultiValueGetCount(socialRef); i++) {
NSDictionary *socialDictionary = (__bridge NSDictionary *)ABMultiValueCopyValueAtIndex(socialRef, i);
if ([socialDictionary[#"service"] isEqualToString:(__bridge NSString *)kABPersonSocialProfileServiceFacebook]) {
[theContactInfoDictionary setObject:(NSString *)socialDictionary[#"username"] forKey:#"theFacebook"];
} else if ([socialDictionary[#"service"] isEqualToString:(__bridge NSString *)kABPersonSocialProfileServiceTwitter]) {
[theContactInfoDictionary setObject:(NSString *)socialDictionary[#"username"] forKey:#"theTwitter"];
} else if ([socialDictionary[#"service"] isEqualToString:#"Google+"]) {
[theContactInfoDictionary setObject:(NSString *)socialDictionary[#"username"] forKey:#"theGoogle"];
}
}
CFRelease(socialRef);
I think I need to use ABMultiValueCopyArrayOfAllValues to grab all phone numbers from my ABAddressBookRef reference variable.
(If this is not the correct way to do it, please give me a correct way; ANY way that gives me access to contact phone numbers will do)
What I'd like to do now, is grab my user's contact's phone numbers(preferably their cell) and add that to an array.
How do I grab just the numbers and add that to an array?
Any help, suggestions, or advice with this is greatly appreciated in advice, I'm not finding this anywhere.
Thanks.
If I were you, I would use this approach:
NSMutableArray *allPhoneNumbers = #[].mutableCopy;
NSArray *allContact = (__bridge NSArray*)ABAddressBookCopyArrayOfAllPeople(book);
for (id rec in allContacts){
ABMultiValueRef mvr = ABRecordCopyValue((__bridge ABRecordRef)rec, kABPersonPhoneProperty);
NSArray *currentNums = (__bridge NSArray*) ABMultiValueCopyArrayOfAllValues(mvr);
[allPhoneNumbers addObjectsFromArray: currentNums];
}
I have not tested this, but it should work. Tell me if you have any issues.
If you want just one contact's numbers (the above gets every contact), use this code.
ABMultiValueRef mvr = ABRecordCopyValue(yourRecordRef, kABPersonPhoneProperty);
NSArray *currentNums = (__bridge NSArray*) ABMultiValueCopyArrayOfAllValues(mvr);
[allPhoneNumbers addObjectsFromArray: currentNums];
ABMultiValueRef phoneNumbers = ABRecordCopyValue(ref, kABPersonPhoneProperty);
for(CFIndex j = 0; j < ABMultiValueGetCount(phoneNumbers); j++)
{
CFStringRef phoneNumberRefCF = ABMultiValueCopyValueAtIndex(phoneNumbers, j);
CFStringRef locLabelCF = ABMultiValueCopyLabelAtIndex(phoneNumbers, j);
NSString *phoneLabelCF =(NSString*) ABAddressBookCopyLocalizedLabel(locLabelCF);
NSString *phoneNumberCF = (NSString *)phoneNumberRefCF;
CFRelease(phoneNumberRefCF);
CFRelease(locLabelCF);
NSLog(#" - %# (%#)", phoneNumberCF, phoneLabelCF);
}