I want to link the address book view controller in my app , I have searched the internet and found in apple developer guide but they show how to open contacts picker when clicking on a button and I don't want that I want the contacts picker be a view controller in my storyboard . I think i can do that by making a custom tableviewcontroller and getting information from address book or can I do it directly ?
This should help you get started:
Also, don't forget to import and link to the following frameworks:
#import <AddressBookUI/AddressBookUI.h>
#import <AddressBook/AddressBook.h>
Simply call: [self requestPermissionForContacts];
- (void)requestPermissionForContacts
{
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined)
{
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error)
{
if (granted)
{
dispatch_async(dispatch_get_main_queue(), ^
{
[self findContacts];
});
}
else
{
dispatch_async(dispatch_get_main_queue(), ^
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Find Contacts" message:#"To allow us to find your contacts, you will need to go to the Settings app > Privacy > Contacts, and set your app name here to On." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
});
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized)
{
[self findContacts];
}
else
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Find Contacts" message:#"To allow us to find your contacts, you will need to go to the Settings app > Privacy > Contacts, and set your app name here to On." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
- (void)findContacts
{
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
CFIndex numberOfPeople = CFArrayGetCount(people);
if (numberOfPeople > 0)
{
NSMutableArray *mutableEmailsArray = [[NSMutableArray alloc]init];
NSMutableArray *mutablePhonesArray = [[NSMutableArray alloc]init];
for (int i = 0; i < numberOfPeople; i++)
{
ABRecordRef ref = CFArrayGetValueAtIndex(people, i);
ABMultiValueRef emails = (__bridge ABMultiValueRef)((__bridge NSString*)ABRecordCopyValue(ref, kABPersonEmailProperty));
ABMultiValueRef phones = (__bridge ABMultiValueRef)((__bridge NSString*)ABRecordCopyValue(ref, kABPersonPhoneProperty));
if (ABMultiValueGetCount(emails) > 0)
{
[mutableEmailsArray addObjectsFromArray:((__bridge NSArray *)(ABMultiValueCopyArrayOfAllValues(emails)))];
}
if (ABMultiValueGetCount(phones) > 0)
{
[mutablePhonesArray addObjectsFromArray:((__bridge NSArray *)(ABMultiValueCopyArrayOfAllValues(phones)))];
}
}
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:nil message:[NSString stringWithFormat:#"%ld Emails %ld Phone Numbers", (unsigned long)mutableEmailsArray.count, (unsigned long)mutablePhonesArray.count] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
else
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"No Contacts" message:#"No contacts were found on your device." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
Related
I am developing an application in which I want to fetch contacts who are using the same application from my contact list in iphone.
How to do it? Any sample code or link ?
Please help me.
Note : I don't want to fetch all contacts in my ios application, I
just want to fetch the contacts who are using the same application.
import AddressBook framework first
Then call these two functions
-(void)AddressBookFetch{
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status == kABAuthorizationStatusDenied || status == kABAuthorizationStatusRestricted) {
// if you got here, user had previously denied/revoked permission for your
// app to access the contacts, and all you can do is handle this gracefully,
// perhaps telling the user that they have to go to settings to grant access
// to contacts
[[[UIAlertView alloc] initWithTitle:nil message:#"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
return;
}
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (!addressBook) {
NSLog(#"ABAddressBookCreateWithOptions error: %#", CFBridgingRelease(error));
return;
}
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (error) {
NSLog(#"ABAddressBookRequestAccessWithCompletion error: %#", CFBridgingRelease(error));
}
if (granted) {
// if they gave you permission, then just carry on
[self listPeopleInAddressBook:addressBook];
} else {
// however, if they didn't give you permission, handle it gracefully, for example...
dispatch_async(dispatch_get_main_queue(), ^{
// BTW, this is not on the main thread, so dispatch UI updates back to the main queue
[[[UIAlertView alloc] initWithTitle:nil message:#"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
});
}
CFRelease(addressBook);
});
}
Then list contact by this function
- (void)listPeopleInAddressBook:(ABAddressBookRef)addressBook
{
NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
numberOfPeople = [allPeople count];
for (NSInteger i = 0; i < numberOfPeople; i++) {
ABRecordRef person = (__bridge ABRecordRef)allPeople[i];
NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSLog(#"Name:%# %#", firstName, lastName);
if (firstName==nil) {
firstName=#"";
}
[nm addObject:firstName];
if (lastName==nil) {
lastName=#"";
}
[ttl addObject:lastName];
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
// CFIndex numberOfPhoneNumbers = ABMultiValueGetCount(phoneNumbers);
//for (CFIndex i = 0; i < numberOfPhoneNumbers; i++) {
NSString *phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phoneNumbers, 0));
NSLog(#" phone:%#", phoneNumber);
if (phoneNumber==nil) {
phoneNumber=#"";
}
[phn addObject:phoneNumber];
// }
// CFRelease(phoneNumbers);
NSLog(#"=============================================");
}
}
Its not possible without back-end, you can not do it within only ios application.
I'm trying to add a contact to the address book in iOS8. Unable to do so anymore. Here's my code below:
-(void)addPersonToAddressBook {
NSString * fullName = integrationDictionary[#"fullName"];
ABPeoplePickerNavigationController *pp =[ABPeoplePickerNavigationController new];
ABAddressBookRef addressBook = [pp addressBook];
ABRecordRef entry = ABPersonCreate();
CFErrorRef cfError=nil;
ABRecordSetValue(entry, kABPersonFirstNameProperty, (__bridge CFTypeRef)(fullName) , nil);
ABAddressBookAddRecord(addressBook, entry, &cfError);
if (ABAddressBookSave(addressBook, &cfError)) {
NSString *saveMessage = [NSString stringWithFormat:#"%# has been added to your address book.", fullName];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Contact Added" message:saveMessage delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
} else {
NSString *saveMessage = [NSString stringWithFormat:#"There was an error adding %# to your address book.", fullName];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Uh Oh" message:saveMessage delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
NSLog(#"error is %#", cfError);
The error is showing up as null. Has anyone seen this before? Any workarounds?
The error is returning NULL because there's no error registered.
The problem is that [pp addressBook] is returning nil. So your ABAddressBookRef addressBook reference is nil.
The workaround is to use ABAddressBookCreateWithOptions instead of [pp addressBook] method of ABPeoplePickerNavigationController.
Here's a sample which works just fine on both iOS 7.1 & iOS 8.1:
-(void)requestAuthorizationAndAddPersonToAddressBook
{
// Request authorization to Address Book
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
// First time access has been granted, add the contact
[self addPersonToAddressBook];
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add the contact
[self addPersonToAddressBook];
}
else {
// The user has previously denied access
// Send an alert telling user to change privacy setting in settings app
}
}
-(void)addPersonToAddressBook {
NSString * fullName = #"James Bond";
CFErrorRef abCreateError = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &abCreateError);
if (abCreateError) {
NSLog(#"Error occurred: %#", abCreateError);
}
ABRecordRef entry = ABPersonCreate();
CFErrorRef cfError=nil;
ABRecordSetValue(entry, kABPersonFirstNameProperty, (__bridge CFTypeRef)(fullName) , nil);
ABAddressBookAddRecord(addressBook, entry, &cfError);
if (ABAddressBookSave(addressBook, &cfError)) {
NSString *saveMessage = [NSString stringWithFormat:#"%# has been added to your address book.", fullName];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Contact Added" message:saveMessage delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
} else {
NSString *saveMessage = [NSString stringWithFormat:#"There was an error adding %# to your address book.", fullName];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Uh Oh" message:saveMessage delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
if (cfError) {
NSLog(#"error is %#", cfError);
}
}
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
// First time access has been granted, add the contact
[self prepareContactsIDs];
} else {
UIAlertView *accessDenied = [[UIAlertView alloc] initWithTitle:#"Need Access to Addressbook" message:#"KeepItClean requires an access to addressbook in order to be usable" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[accessDenied show];
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add the contact
if ([self isFirstRun]) {
[self prepareContactsIDs];
}
}
else {
// The user has previously denied access
// Send an alert telling user to change privacy setting in settings app
UIAlertView *accessDenied = [[UIAlertView alloc] initWithTitle:#"Need Access to Addressbook" message:#"KeepItClean requires an access to addressbook in order to be usable" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[accessDenied show];
}
There is something i don't understand here, when the user is prompted to give access, if he taps cancel, i don't get my 2nd UIAlertView showing up, the (accessDenied) alert view.
Also i feel there is something i don't understand that is related to dispatching and queues.
Try this
ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
peoplePicker.peoplePickerDelegate= self;
ABAddressBookRef UsersAddressBook = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus()!= kABAuthorizationStatusDenied)
{
//Show alert of access
}
else
{
//Show alert of access denied
}
I would like my app to only ask the user for permission to access the Contacts addressbook until the user access the proper function in my app. I really don't want to request permission when the app loads.
As a result I've used the following code:
- (IBAction)importClientsButtonPressed:(id)sender {
// request access to Contacts address book
CFErrorRef addyError = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &addyError);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef addyError) {
});
}
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
_importContactsActionSheet = [[UIActionSheet alloc] initWithTitle:#"Import Client from Contacts"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Primary Contact", #"Secondary Contact", nil];
_importContactsActionSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[_importContactsActionSheet showFromRect:self.importClientsButton.frame inView:self.importClientsButton.superview animated:YES];
} else {
// the user has previously denied access - send alert to user to allow access in Settings app
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Privacy Settings"
message:#"This app does not have access to your contacts. You can enable access in Privacy Settings."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
However, the permission dialog does not halt the app and wait for a response...the code following the request continues to run. As a result I get a whack of messages popping up out of order.
Is there any way to have the whole app halt until a response comes back from the permission request dialog?
Thanks!
In your code above also you have this:
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef addyError) {
if(granted) {
//Put here your code
}
});
so finally i would write the code in this way:
- (IBAction)importClientsButtonPressed:(id)sender {
__weak typeof(self) weakSelf = self;
// request access to Contacts address book
CFErrorRef addyError = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &addyError);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef addyError) {
if(granted) {
[weakSelf openImportContact];
}
});
} else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
[weakSelf openImportContact];
} else {
// the user has previously denied access - send alert to user to allow access in Settings app
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Privacy Settings"
message:#"This app does not have access to your contacts. You can enable access in Privacy Settings."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
- (void)openImportContact {
dispatch_async(dispatch_get_main_queue(), ^{
_importContactsActionSheet = [[UIActionSheet alloc] initWithTitle:#"Import Client from Contacts"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Primary Contact", #"Secondary Contact", nil];
_importContactsActionSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[_importContactsActionSheet showFromRect:self.importClientsButton.frame inView:self.importClientsButton.superview animated:YES];
});
}
I have a simple form that is only taking four fields right now (I'll add in more later)
First Name
Last Name
Home Email
Work Email
I only want to save items that have a value as a new contact. Right now, if I don't enter in a value, then in the contact page the value is "NULL". What is the appropriate way to handle this?
Here is my code
#pragma mark - Add New Contacts Methods
- (IBAction)savePublicContact:(UIBarButtonItem *)sender {
CFErrorRef anError = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &anError);
ABRecordRef person = ABPersonCreate();
Person *personUserDefined = [self populatePersonToSave];
ABRecordSetValue(person,kABPersonFirstNameProperty,(__bridge CFTypeRef)(personUserDefined.firstName),&anError);
ABRecordSetValue(person,kABPersonLastNameProperty,(__bridge CFTypeRef)(personUserDefined.lastName),&anError);
ABMutableMultiValueRef emailMultiValue = ABMultiValueCreateMutable(kABPersonEmailProperty);
ABMultiValueAddValueAndLabel(emailMultiValue, (__bridge CFTypeRef)(personUserDefined.homeEmail), (CFStringRef)#"Home Email", NULL);
ABMultiValueAddValueAndLabel(emailMultiValue, (__bridge CFTypeRef)(personUserDefined.workEmail), (CFStringRef)#"Work Email", NULL);
ABRecordSetValue(person, kABPersonEmailProperty, emailMultiValue, &anError);
ABAddressBookAddRecord(addressBook, person, &anError);
if(ABAddressBookSave(addressBook, &anError)){
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Added Contact"
message:#"You successfully added a contact"
delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
}else{
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Contact Error"
message:(#"Contact was not able to be added")
delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
}
}
- (Person *)populatePersonToSave
{
Person *person = [[Person alloc] init];
if([self.firstNameToSaveTextField.text length] > 0){
person.firstName = self.firstNameToSaveTextField.text;
}
if([self.lastNameToSaveTextField.text length] > 0) {
person.lastName = self.lastNameToSaveTextField.text;
}
if([self.workEmailToSaveTextField.text length] > 0){
person.workEmail = self.workEmailToSaveTextField.text;
}
if([self.homeEmailToSaveTextField.text length] > 0){
person.homeEmail = self.homeEmailToSaveTextField.text;
}
return person;
}
Better you put the check for null condition where you are adding contact to address-book, its because at every time you are initiating the required field in contact list .if you have no data to input in required field why should we initiate it or refer it.
Better you use the modified code:
if (personUserDefined.firstName) {
ABRecordSetValue(person,kABPersonFirstNameProperty,(__bridge CFTypeRef)(personUserDefined.firstName),&anError);
}
if (personUserDefined.lastName) {
ABRecordSetValue(person,kABPersonLastNameProperty,(__bridge CFTypeRef)(personUserDefined.lastName),&anError);
}
ABMutableMultiValueRef emailMultiValue = ABMultiValueCreateMutable(kABPersonEmailProperty);
if (personUserDefined.homeEmail) {
ABMultiValueAddValueAndLabel(emailMultiValue, (__bridge CFTypeRef)(personUserDefined.homeEmail), (CFStringRef)#"Home Email", NULL);
}
if (personUserDefined.workEmail) {
ABMultiValueAddValueAndLabel(emailMultiValue, (__bridge CFTypeRef)(personUserDefined.workEmail), (CFStringRef)#"Work Email", NULL);
}
ABRecordSetValue(person, kABPersonEmailProperty, emailMultiValue, &anError);
ABAddressBookAddRecord(addressBook, person, &anError);
above code provide you how to prevent inserting null values in addressbook. please check if condition satisfying conditions (i had not executed on system).
#pragma mark - Add New Contacts Methods
- (IBAction)savePublicContact:(UIBarButtonItem *)sender {
CFErrorRef anError = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &anError);
ABRecordRef person = ABPersonCreate();
if([self isvalidDetails]){ //New method to validate details - this will return yes/no based on validation
Person *personUserDefined = [self populatePersonToSave];
ABRecordSetValue(person,kABPersonFirstNameProperty,(__bridge CFTypeRef)(personUserDefined.firstName),&anError);
ABRecordSetValue(person,kABPersonLastNameProperty,(__bridge CFTypeRef)(personUserDefined.lastName),&anError);
ABMutableMultiValueRef emailMultiValue = ABMultiValueCreateMutable(kABPersonEmailProperty);
ABMultiValueAddValueAndLabel(emailMultiValue, (__bridge CFTypeRef)(personUserDefined.homeEmail), (CFStringRef)#"Home Email", NULL);
ABMultiValueAddValueAndLabel(emailMultiValue, (__bridge CFTypeRef)(personUserDefined.workEmail), (CFStringRef)#"Work Email", NULL);
ABRecordSetValue(person, kABPersonEmailProperty, emailMultiValue, &anError);
ABAddressBookAddRecord(addressBook, person, &anError);
if(ABAddressBookSave(addressBook, &anError)){
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Added Contact"
message:#"You successfully added a contact"
delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
}else{
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Contact Error"
message:(#"Contact was not able to be added")
delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
}
}
}
-(BOOL)isValidDetails{
BOOL isValidated = TRUE;
if([self.firstNameToSaveTextField.text length] <= 0){ //Trim and check length
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Required field"
message:(#"Please enter firstname")
delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
isValidated = FALSE;
return isValidated;
}
if([self.lastNameToSaveTextField.text length] > 0) {
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Required field"
message:(#"Please enter lastname")
delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
isValidated = FALSE;
return isValidated;
}
if([self.workEmailToSaveTextField.text length] > 0){
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Required field"
message:(#"Please enter work email")
delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
isValidated = FALSE;
return isValidated;
}
if([self.homeEmailToSaveTextField.text length] > 0){
UIAlertView *alertsuccess = [[UIAlertView alloc] initWithTitle:#"Required field"
message:(#"Please enter home email")
delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertsuccess show];
isValidated = FALSE;
return isValidated;
}
return isValidated;
}
- (Person *)populatePersonToSave
{
Person *person = [[Person alloc] init];
if([self.firstNameToSaveTextField.text length] > 0){
person.firstName = self.firstNameToSaveTextField.text;
}
if([self.lastNameToSaveTextField.text length] > 0) {
person.lastName = self.lastNameToSaveTextField.text;
}
if([self.workEmailToSaveTextField.text length] > 0){
person.workEmail = self.workEmailToSaveTextField.text;
}
if([self.homeEmailToSaveTextField.text length] > 0){
person.homeEmail = self.homeEmailToSaveTextField.text;
}
return person;
}