系统通讯录的使用之基于 Contacts.framework 和 ContactsUI.framework 框架的实现

与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 *)contacts;
//多选 列表页选中多个联系人后返回多个属性
//需要执行 返回被选中多个联系人的property 前提需设置:_contactPicker.predicateForSelectionOfProperty = [NSPredicate predicateWithValue:true];
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperties:(NSArray *)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属性之间的对应关系。

你可能感兴趣的:(系统通讯录的使用之基于 Contacts.framework 和 ContactsUI.framework 框架的实现)