While sending SMS through my app,it should sent it to mobile only but for some contacts when two numbers are there one is landline and other is mobile it sends to landline also.
- (NSMutableArray*)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"];
}
NSLog(#"ABMultiValueGetCount(phones)=%ld",ABMultiValueGetCount(phones));
//For Phone number
NSString* mobileLabel;
for(CFIndex i = 0; i < ABMultiValueGetCount(phones); i++) {
mobileLabel = (__bridge NSString*)ABMultiValueCopyLabelAtIndex(phones, i);
if([mobileLabel isEqualToString:(NSString *)kABPersonPhoneMobileLabel])
{
[dOfPerson setObject:(__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, i) forKey:#"Phone"];
}
else if ([mobileLabel isEqualToString:(NSString*)kABPersonPhoneIPhoneLabel])
{
[dOfPerson setObject:(__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, i) forKey:#"Phone"];
break ;
}
}
[contactList addObject:dOfPerson];
}
return contactList;
}
There's a beautiful port of Google's Phone number handling library libPhoneNumber for iOS.
It can help you distinguish between fixed line, mobile phone, toll-free, premium numbers and much more. You can add this library to your project using Cocoapods and follow the README for documentation.
Here's the link (iOS Port): https://github.com/iziz/libPhoneNumber-iOS
Google libphonenumber library (For Android): https://github.com/googlei18n/libphonenumber
Both of them carry almost the same functionality and are very accurate in detecting whether the number is valid or not. It saved us a lot of time and money whenever we encountered a phone number incapable of receiving SMS such as that of a landline.
However, as mentioned in the comments as well, most of the fixed line or landline numbers are capable of receiving SMS, in that case, you should ask the user whether they want to have an SMS on specified number or not.
Thank You
Fennec
Happy Coding!
Related
First a quick background, I hired a developer to build my app however I know that I learn better by dissecting existing code so my goal is to learn more about iOS programming this way rather than paying the developer to fix.
Now, the app is crashing when I am importing a contact from the address book into the app. I have noticed that the app crash happens when I import a contact from the iOS Facebook contacts but not other groups of contacts. What could be causing this?
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
Triggered by Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
Research tells me that the app is trying to call something it does not have access to but not sure where to go from here.
Here is the area of code that I believe is causing the issue. (This action).
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
[_addressBookController dismissViewControllerAnimated:YES completion:nil];
}
-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{
_arrContactsData =[[NSMutableArray alloc] init];
NSMutableDictionary *contactInfoDict = [[NSMutableDictionary alloc]
initWithObjects:#[#"", #"", #"", #"", #"", #"", #"", #"", #""]
forKeys:#[#"firstName", #"lastName", #"mobileNumber", #"homeNumber", #"homeEmail", #"workEmail", #"address", #"zipCode", #"city"]];
// Use a general Core Foundation object.
CFTypeRef generalCFObject = ABRecordCopyValue(person, kABPersonFirstNameProperty);
// Get the first name.
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"firstName"];
CFRelease(generalCFObject);
}
// Get the last name.
generalCFObject = ABRecordCopyValue(person, kABPersonLastNameProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"lastName"];
CFRelease(generalCFObject);
}
// Get the phone numbers as a multi-value property.
ABMultiValueRef phonesRef = ABRecordCopyValue(person, kABPersonPhoneProperty);
for (int i=0; i<ABMultiValueGetCount(phonesRef); i++) {
CFStringRef currentPhoneLabel = ABMultiValueCopyLabelAtIndex(phonesRef, i);
CFStringRef currentPhoneValue = ABMultiValueCopyValueAtIndex(phonesRef, i);
if (CFStringCompare(currentPhoneLabel, kABPersonPhoneMobileLabel, 0) == kCFCompareEqualTo) {
[contactInfoDict setObject:(__bridge NSString *)currentPhoneValue forKey:#"mobileNumber"];
}
if (CFStringCompare(currentPhoneLabel, kABHomeLabel, 0) == kCFCompareEqualTo) {
[contactInfoDict setObject:(__bridge NSString *)currentPhoneValue forKey:#"homeNumber"];
}
CFRelease(currentPhoneLabel);
CFRelease(currentPhoneValue);
}
CFRelease(phonesRef);
// Get the e-mail addresses as a multi-value property.
ABMultiValueRef emailsRef = ABRecordCopyValue(person, kABPersonEmailProperty);
for (int i=0; i<ABMultiValueGetCount(emailsRef); i++) {
CFStringRef currentEmailLabel = ABMultiValueCopyLabelAtIndex(emailsRef, i);
CFStringRef currentEmailValue = ABMultiValueCopyValueAtIndex(emailsRef, i);
if (CFStringCompare(currentEmailLabel, kABHomeLabel, 0) == kCFCompareEqualTo) {
[contactInfoDict setObject:(__bridge NSString *)currentEmailValue forKey:#"homeEmail"];
}
if (CFStringCompare(currentEmailLabel, kABWorkLabel, 0) == kCFCompareEqualTo) {
[contactInfoDict setObject:(__bridge NSString *)currentEmailValue forKey:#"workEmail"];
}
CFRelease(currentEmailLabel);
CFRelease(currentEmailValue);
}
CFRelease(emailsRef);
// Get the first street address among all addresses of the selected contact.
ABMultiValueRef addressRef = ABRecordCopyValue(person, kABPersonAddressProperty);
if (ABMultiValueGetCount(addressRef) > 0) {
NSDictionary *addressDict = (__bridge NSDictionary *)ABMultiValueCopyValueAtIndex(addressRef, 0);
[contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressStreetKey] forKey:#"address"];
[contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressZIPKey] forKey:#"zipCode"];
[contactInfoDict setObject:[addressDict objectForKey:(NSString *)kABPersonAddressCityKey] forKey:#"city"];
}
CFRelease(addressRef);
// If the contact has an image then get it too.
if (ABPersonHasImageData(person)) {
NSData *contactImageData = (__bridge NSData *)ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail);
[contactInfoDict setObject:contactImageData forKey:#"image"];
}
// Initialize the array if it's not yet initialized.
if (_arrContactsData == nil) {
_arrContactsData = [[NSMutableArray alloc] init];
}
// Add the dictionary to the array.
[_arrContactsData addObject:contactInfoDict];
// Reload the table view data.
// Dismiss the address book view controller.
[_addressBookController dismissViewControllerAnimated:YES completion:nil];
NSDictionary *info = [_arrContactsData objectAtIndex:0];
self.txfFirstName.text = [info objectForKey:#"firstName"];
self.txfLastName.text = [info objectForKey:#"lastName"];
self.txfMobile.text =[info objectForKey:#"mobileNumber"];
self.txfEmail.text =[info objectForKey:#"homeEmail"];
NSLog(#"Info %#",info);
return NO;
}
It looks like Facebook labels its email contacts weird in the address book, so that when you query the labels it returns a nil value, which will give you your bad access error and the crash
personally i put an if statement around it and just ignored all nil addresses as i only wanted work addresses anyway, see following example in your code (i haven't checked this but it should work)
After "analyzing" my previous answer I noticed that it actually reported a memory leak so i moved the if around a bit and with the updated code below its gone.
for (int i=0; i<ABMultiValueGetCount(emailsRef); i++) {
CFStringRef currentEmailLabel = ABMultiValueCopyLabelAtIndex(emailsRef, i);
CFStringRef currentEmailValue = ABMultiValueCopyValueAtIndex(emailsRef, i);
if (currentEmailLabel != nil) {
if (CFStringCompare(currentEmailLabel, kABWorkLabel, 0) == kCFCompareEqualTo) {
[self.contactInfoDict setObject:(__bridge NSString *)currentEmailValue forKey:#"workEmail"];
}
CFRelease(currentEmailLabel);
}
CFRelease(currentEmailValue);
}
CFRelease(emailsRef);//END OF IF WRAPPER
if you want the emails and don't care that they are Facebook I imagine you could just do a nil check on the label and relabel it or just ignore the label compare completely.
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.
Guys am working on a calling app for Ios,so naturally i have a dial-pad integrated.
The problem am facing in to get the contact details from number dialed from my dial-pad which i am showing in other screen.
Here is my code
+(PhoneContactModel*) getContactFrom:(NSString *)calledPhoneNumber{
PhoneContactModel *contact=[[PhoneContactModel alloc]init];
ABAddressBookRef addressBook = [AppUtils getCompatibleAdressBook];
CFArrayRef all = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex n = ABAddressBookGetPersonCount(addressBook);
for( int i = 0 ; i < n ; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex(all, i);
ABMultiValueRef phones = (ABMultiValueRef)ABRecordCopyValue(ref, kABPersonPhoneProperty);
for(CFIndex j = 0; j < ABMultiValueGetCount(phones); j++)
{
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(phones, j);
//CFRelease(phones);
NSString *phoneNumber = (__bridge NSString *)phoneNumberRef;
NSLog(#"apputil number %#",[AppUtils getNumberSanatized:phoneNumber]);
if ([phoneNumber isEqualToString:calledPhoneNumber]){
NSLog(#"apputil number matched %#",[AppUtils getNumberSanatized:phoneNumber]);
contact.strFullName = (__bridge_transfer NSString *) ABRecordCopyValue(ref, kABPersonFirstNameProperty);
NSString *lastName = (__bridge_transfer NSString *) ABRecordCopyValue(ref, kABPersonLastNameProperty);
contact.strFullName=[contact.strFullName stringByAppendingString:#" "];
if (lastName!=nil){
contact.strFullName=[contact.strFullName stringByAppendingString:lastName];
}
contact.imgContactImge=[AppUtils imageForContact:ref];
contact.strNumber=phoneNumber;
return contact;
}
}
}
contact.strFullName = calledPhoneNumber;
return contact;
}
The problem appears like if i have a Contact A with number 64xxxx... and i dial +164xxxx.. from my dial-pad i don't get the contact details, Also you can see that in the method above i have to run a loop to find the matching contact even if there is a match, so is there a better method out there to do the same
Thanks
I created a better solution
it can be seen here http://codesnight.blogspot.in/2013/11/ios-acces-contacts-from-number.html
I am using the following code to get mobile number (i.e. 1st phone number) of all contacts in my address book. I want to store all those number into NSArray
self.dataSource = [[NSMutableArray alloc]init]; // dataSouce is delared in .h file
ABAddressBookRef addressBook = ABAddressBookCreate();
NSMutableArray *allPeople = (__bridge NSMutableArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
int nPeople = ABAddressBookGetPersonCount(addressBook);
for(int i=0; i < nPeople; i++ ){
ABRecordRef person = (__bridge ABRecordRef)([allPeople objectAtIndex:i]);
NSString *name = #"";
if(ABRecordCopyValue(person, kABPersonFirstNameProperty) != NULL)
name = [[NSString stringWithFormat:#"%#", ABRecordCopyValue(person, kABPersonFirstNameProperty)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[_dataSource addObject: name];
ABMultiValueRef phoneNumberProperty = ABRecordCopyValue(person, kABPersonPhoneProperty);
_phoneNumbers = (__bridge NSArray*)ABMultiValueCopyValueAtIndex(phoneNumberProperty, 0);
CFRelease(phoneNumberProperty);
NSLog(#"Phone numbers = %#", _phoneNumbers);
}
but when I use NSLog(#"Phone numbers = %#", _phoneNumbers); the output comes out as
2012-11-07 15:31:06.116 contacts[4938:12b03] Phone numbers = 1 (800) 111-1111
2012-11-07 15:31:06.117 contacts[4938:12b03] Phone numbers = (222) 355-5668
2012-11-07 15:31:06.118 contacts[4938:12b03] Phone numbers = (910) 192-0192
I want the output in NSArray like
Phone numbers = (
"1 (800) 111-1111",
"(222) 355-5668",
"(910) 192-0192"
)
how can I do this ?
you Can Do it Simply like this
self.dataSource = [[NSMutableArray alloc]init]; // dataSouce is delared in .h file
ABAddressBookRef addressBook = ABAddressBookCreate();
NSMutableArray *allPeople = (__bridge NSMutableArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
int nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray *arrContacts = [[NSMutableArray alloc] init];
for(int i=0; i < nPeople; i++ ){
ABRecordRef person = (__bridge ABRecordRef)([allPeople objectAtIndex:i]);
NSString *name = #"";
if(ABRecordCopyValue(person, kABPersonFirstNameProperty) != NULL)
name = [[NSString stringWithFormat:#"%#", ABRecordCopyValue(person, kABPersonFirstNameProperty)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[_dataSource addObject: name];
ABMultiValueRef phoneNumberProperty = ABRecordCopyValue(person, kABPersonPhoneProperty);
_phoneNumbers = (__bridge NSArray*)ABMultiValueCopyValueAtIndex(phoneNumberProperty, 0);
CFRelease(phoneNumberProperty);
NSLog(#"Phone numbers = %#", _phoneNumbers);
[arrContacts addObject:_phoneNumbers];
}
NSLog(#"Phone numbers : %#",arrContacts);
I found this via Google and was using this address book code as an example, but found a mistake that I'd correct for others coming here.
When using ABMultiValueCopyValueAtIndex it returns a type CFTypeRef. That function gets just the phone number at that index (in this case at index 0) which in the case of the phone number is a CFStringRef that shouldn't be cast to an NSArray*.
ABMultiValueCopyArrayOfAllValues would be the proper call to get the array of all phone numbers stored in a contact. That can be stored into an array and logged like Sarafaraz is doing in his answer.
NSArray *_phoneNumbers = (__bridge NSArray*)ABMultiValueCopyArrayOfAllValues(phoneNumberProperty);
If you just want to get the first phone number you would do this:
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(phoneNumberProperty, 0);
NSString *phoneString = (__bridge NSString*)phoneNumberRef;
I am using an ABPeoplePickerNavigationController to collect an array of email addresses and phone numbers from a contact book entry. 90% of the time it works fine but a few testers are reporting crashes. The crash report says it is crashing at CFRelease ... Not sure why considering I believe my code is correct. Take a look:
ABProfile *selectedUser = [[ABProfile alloc]init];
ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
NSArray *emailArray;
if (ABMultiValueGetCount(emails) > 0) {
emailArray = (__bridge_transfer NSArray *)ABMultiValueCopyArrayOfAllValues(emails);
}
CFRelease(emails);
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
NSMutableArray *phonesArray = [[NSMutableArray alloc]initWithCapacity:1];
for(CFIndex j = 0; j < ABMultiValueGetCount(phones); j++)
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc]initWithCapacity:1];
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(phones, j);
CFStringRef locLabel = ABMultiValueCopyLabelAtIndex(phones, j);
NSString *phoneLabel =(__bridge_transfer NSString*) ABAddressBookCopyLocalizedLabel(locLabel);
CFRelease(locLabel);
[dict setValue:phoneLabel forKey:#"label"];
NSString *phoneNumber = (__bridge_transfer NSString *)phoneNumberRef;
[dict setValue:phoneNumber forKey:#"number"];
[phonesArray addObject:dict];
}
selectedUser.phones = phonesArray;
CFRelease(phones);
ABMultiValueCopyLabelAtIndex can return NULL if not found, and CFRelease(NULL) will crash. I would cheek to ensure locLabel exists before doing anything with it.