How do I customize the UI of the CNContactPickerViewController?
I want to alter the colors, fonts, and text - similar to how snapchat has done?
Currently - my CNContactPickerViewController looks exactly like Apple's native contacts app.
First get contacts from address book and pass them into an NSArray:
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
NSMutableArray *contacts = [NSMutableArray array];
NSError *fetchError;
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:#[CNContactIdentifierKey, [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]]];
BOOL success = [store enumerateContactsWithFetchRequest:request error:&fetchError usingBlock:^(CNContact *contact, BOOL *stop) {
[contacts addObject:contact];
}];
if (!success) {
NSLog(#"error = %#", fetchError);
}
}];
Then simply use the NSArray in a UITableView and from there you can customize the font, colors, etc.
Related
Settings>Contacts>Default Account selected as iCloud and saved a new contact.Then changed Default Account as gmail. CNContactStore not fetching the new saved contact.
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted == YES)
{
NSArray *keys = #[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPhoneNumbersKey, CNContactImageDataKey,CNContactEmailAddressesKey];
NSArray * contactContainerArray = [store containersMatchingPredicate:nil error:nil];
for(CNContainer * container in contactContainerArray) {
NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:container.identifier];
NSError *error;
NSArray *cnContacts = [store unifiedContactsMatchingPredicate:predicate keysToFetch:keys error:&error];
}
If you simply wish to get all unified contacts (Contacts in different accounts that represent the same person may be automatically linked together. Linked contacts are displayed in macOS and iOS apps as unified contacts) the best solution would be below one
-(void)fetchContacts
{
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted == YES)
{
//keys with fetching properties
NSArray *keys = #[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPhoneNumbersKey, CNContactImageDataKey,CNContactEmailAddressesKey];
NSString *containerId = store.defaultContainerIdentifier;
NSArray * contactContainerArray = [store containersMatchingPredicate:nil error:nil];
CNContactFetchRequest * fetchRequest = [[CNContactFetchRequest alloc]initWithKeysToFetch:keys];
[store enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
}];
}
}
How to display contact in table view?
I have fetched the contacts via CNContactStore iOS 9.
- (void) getContacts {
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted == YES) {
//keys with fetching properties
NSArray *keys = #[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPhoneNumbersKey,CNContactImageDataKey];
NSString *containerId = store.defaultContainerIdentifier;
NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:containerId];
NSError *error;
NSArray *cnContactsarray = [store unifiedContactsMatchingPredicate:predicate keysToFetch:keys error:&error];
if (error) {
NSLog(#"error fetching contacts %#", error);
}
else {
for (CNContact *contact in cnContactsarray) {
//store all the contacts as per your requirement
NSLog(#"Name : %#",contact.givenName);
NSLog(#"Id : %#",contact.identifier);//the contact id which you want
[_ContactsCN addObject:contact];
}
}
NSLog(#"array %#",_ContactsCN);
}
}];
}
Any help will be appreciated.
You need to reload data on main thread when your fetch contact from CNContact is complete
to run on main thread
dispatch_async(dispatch_get_main_queue(), ^{// reload your table here
});
I want to delete contact from phone contact from my app, as this ABAddressBookRemoveRecord method is deprecated in i os 9. so now how can i delete contact.
Is there any method in contacts framework??
Thanks Everyone!
The complete AddressBook Framework was deprecated in iOS9, you should check out the Contacts Framework instead:
Contacts Framework
A nice tutorial explaining deleting records here.
The tutorial covers Swift, but the same principle applys to Objective-C as well.
Here is the code if you want to delete all contacts in one go using CNContacts
- (void) deleteAllContacts {
CNContactStore *contactStore = [[CNContactStore alloc] init];
[contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted == YES) {
NSArray *keys = #[CNContactPhoneNumbersKey];
NSString *containerId = contactStore.defaultContainerIdentifier;
NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:containerId];
NSError *error;
NSArray *cnContacts = [contactStore unifiedContactsMatchingPredicate:predicate keysToFetch:keys error:&error];
if (error) {
NSLog(#"error fetching contacts %#", error);
} else {
CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init];
for (CNContact *contact in cnContacts) {
[saveRequest deleteContact:[contact mutableCopy]];
}
[contactStore executeSaveRequest:saveRequest error:nil];
DDLogVerbose(#"Deleted contacts %lu", cnContacts.count);
}
}
}];
}
I am using this code to export contact from ios phonebook to .vcf file. I have used this code for the task. But vcardString is always returning nil. Please help me to solve this issue.
NSMutableArray *contacts=[NSMutableArray alloc] init];
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!granted) {
dispatch_async(dispatch_get_main_queue(), ^{
});
return;
}
NSMutableArray *contacts = [NSMutableArray array];
NSError *fetchError;
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:#[CNContactIdentifierKey, [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]]];
BOOL success = [store enumerateContactsWithFetchRequest:request error:&fetchError usingBlock:^(CNContact *contact, BOOL *stop) {
[contacts addObject:contact];
}];
if (!success) {
NSLog(#"error = %#", fetchError);
}
// you can now do something with the list of contacts, for example, to show the names
CNContactFormatter *formatter = [[CNContactFormatter alloc] init];
for (CNContact *contact in contacts) {
[contactsArray addObject:contact];
// NSString *string = [formatter stringFromContact:contact];
//NSLog(#"contact = %#", string);
}
//NSError *error;
NSData *vcardString =[CNContactVCardSerialization dataWithContacts:contactsArray error:&error];
NSLog(#"vcardString = %#",vcardString);
}];
Change this line:
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:#[[CNContactVCardSerialization descriptorForRequiredKeys]]
This fetches all required info for creating a vCard.
AddressBook api is deprecated in ios 9. I want to load all contacts in an array and display it in a UITableView. I don't want to use iOS default ContactPicker as I have to do some customization while displaying. How to load all contact list in an array for further use?
First I had to check the permission id it is not defined then ask for permission for accessing contacts. Like this:
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
if (status == CNAuthorizationStatusNotDetermined) {
[self.contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError *error) {
if (granted) {
[self loadUserListFromPhoneBook];
}
}];
}
else if(status == CNAuthorizationStatusAuthorized) {
[self loadUserListFromPhoneBook];
}
After that I had to iterate through the contact list and load all contacts like this:
-(void) loadUserListFromPhoneBookFor
{
NSMutableArray *contacts = [NSMutableArray array];
NSError *error;
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:#[CNContactIdentifierKey, [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]]];
BOOL success = [self.contactStore enumerateContactsWithFetchRequest:request error:&error usingBlock:^(CNContact *contact, BOOL *stop) {
[contacts addObject:contact];
}];
if (!success) {
NSLog(#"error = %#", error);
}
CNContactFormatter *formatter = [[CNContactFormatter alloc] init];
for (CNContact *contact in contacts) {
NSString *string = [formatter stringFromContact:contact];
NSLog(#"contact = %#", string);
}
}
You can use necessary keys for getting more information. Have a look at this for more information. Its has all new contact classes. This video of WWDC helped a lot.