与ABPeoplePickerNavigationController相似,通过 CNContactPickerViewController 直接调取系统通讯录,只需要通过代理方法处理相应的需求即可。
CNContactPickerDelegate代理方法:
//点击调起页面的“取消”按钮时调用
- (void)contactPickerDidCancel:(CNContactPickerViewController *)picker;
//单选 列表页选中联系人返回
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact;
//单选 联系人详情页选中具体属性返回
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty;
//多选 列表页选中多个联系人后返回多个联系人
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContacts:(NSArray<CNContact*> *)contacts;
//多选 列表页选中多个联系人后返回多个属性
//需要执行 返回被选中多个联系人的property 前提需设置:_contactPicker.predicateForSelectionOfProperty = [NSPredicate predicateWithValue:true];
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperties:(NSArray<CNContactProperty*> *)contactProperties;
获取用户通讯录中所有联系人信息:
CNContactStore *contactStore = [[CNContactStore alloc] init];
NSError *error;
NSArray *keys = @[CNContactPhoneNumbersKey,CNContactFamilyNameKey,CNContactGivenNameKey];
NSArray *allContacts = [contactStore unifiedContactsMatchingPredicate:NULL keysToFetch:keys error:&error];
联系人信息解析过程与AddressBook.framework截然不同:
for (CNContact *contact in allContacts) {
NSString *familyNameString = contact.familyName;
NSString *givenNameString = contact.givenName;
NSArray *mobileArray = contact.phoneNumbers;
for (int i = 0; i < mobileArray.count; i++) {
CNLabeledValue *phoneValue = mobileArray[i];
CNPhoneNumber *phoneNumber = phoneValue.value;
NSString *phoneString = phoneNumber.stringValue;
phoneString = [self filterSymbolFromString:phoneString];
if ([phoneString hasPrefix:numString]) {
self.infoLabel.text = [NSString stringWithFormat:@"%@ (%@%@)", phoneString, familyNameString, givenNameString];
return;
}else {
self.infoLabel.text = @"";
}
}
}
访问权限:
CNContactStore *contactStore = [[CNContactStore alloc] init];
if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] != CNAuthorizationStatusAuthorized) {
[contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!granted) {
UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"尚未获取访问权限" message:@"您未允许PeoploLink访问您的通讯录,请到设置中开启访问通讯录的权限" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *sureAction = [UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
}];
[alertC addAction:sureAction];
[self presentViewController:alertC animated:YES completion:nil];
}else {
NSError *error;
NSArray *keys = @[CNContactPhoneNumbersKey,CNContactFamilyNameKey,CNContactGivenNameKey];
allContacts = [contactStore unifiedContactsMatchingPredicate:[NSPredicate predicateWithFormat:@""] keysToFetch:keys
error:&error];
}
}];
}else {
NSError *error;
NSArray *keys = @[CNContactPhoneNumbersKey,CNContactFamilyNameKey,CNContactGivenNameKey];
allContacts = [contactStore unifiedContactsMatchingPredicate:[NSPredicate predicateWithFormat:@""] keysToFetch:keys
error:&error];
}
添加联系人
- (void)addContact {
NSString *name = @"沙僧";
NSString *phone = @"15101031041";
CNContactStore *contactStore = [[CNContactStore alloc] init];
//初始化单个联系人,注意一定是可变的,不可变的属性是只读的
CNMutableContact *contact = [[CNMutableContact alloc] init];
contact.familyName = name;
//封装电话号码
CNPhoneNumber *phoneNumber = [CNPhoneNumber phoneNumberWithStringValue:phone];
CNLabeledValue *labeledValue = [[CNLabeledValue alloc] initWithLabel:@"手机号码" value:phoneNumber];
NSArray *array = @[labeledValue];
contact.phoneNumbers = array;
//将请求封装成saveRequest
CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init];
//添加单个联系人
[saveRequest addContact:contact toContainerWithIdentifier:nil];
NSError *error = nil;
//执行请求
[contactStore executeSaveRequest:saveRequest error:&error];
NSLog(@"添加联系人成功");
}
删除联系人
- (void)deletePeople {
CNContactStore *contactStore = [[CNContactStore alloc] init];
for (CNContact *contact in allContacts) {
NSString *familyNameString = contact.familyName;
NSString *givenNameString = contact.givenName;
NSString *nameString = [familyNameString stringByAppendingString:givenNameString];
if ([nameString isEqualToString:@"沙僧"]) {
CNSaveRequest *deleteRequest = [[CNSaveRequest alloc] init];
[deleteRequest deleteContact:contact];
NSError *error = nil;
[contactStore executeSaveRequest:deleteRequest error:&error];
NSLog(@"删除联系人成功");
}
}
}
注:
1、由于不同系统、设备等情况下获取的电话号码信息中会存在各种各样的连接符/分隔符,在使用时需要去除/格式化这部分信息。
2、方法执行优先级的看法:列表选中响应和详情选中响应的两个方法不存在优先级的关系,响应了列表选中方法之后,就没有机会再进入详情页,也就不会再响应详情。
3、ABPerson.h中有AddressBook.framework 和Contacts.framework属性之间的对应关系。