在以往的ios开发中,开发者需要获取用户的通讯录信息的时候,往往要使用AddressBook.frame框架,该框架是纯C语言的API,在开发过程中,还需要开发者手动的管理内存,这对于新进开发者很难理解和掌握。到了IOS9,苹果推出了具有OC语言的API,即Contacts框架,该框架理解简单、易于使用。联系人信息可以短时间获取、创建和修改,而且还不需要去关系对象的释放。
下面我们介绍一下Contacts框架:
在ios8以后,苹果更加注重用户的隐私,因此需要访问用户通讯录的时候,必须给用户发送授权请求,得到用户的确认后,才能进行下一步的操作。如果用户不同意,用户禁止APP获取其通讯录信息,那么这个决定必须被APP采纳,且绝对不能与用户的通讯录信息交互。不仅如此,用户随时可以在设置中更改对APP的授权,因此在任何操作的时候,都需要检查用户的授权状态。
//1 判断是否授权成功
if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusAuthorized) return;//授权成功直接返回
//2 创建通讯录
CNContactStore *store = [[CNContactStore alloc] init];
//3授权
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
NSLog(@"授权成功");
}else{
NSLog(@"授权失败");
}
}];
authorizationStatusForEntityType:methods这个方法是CNContactStore的类方法,需要一个 CNEntityType 参数,返回值是授权得到的状态CNAuthorizationStatus,一共有四种,分别为:
- NotDetermined:表示用户还没有允许或禁止访问通讯录数据库。首次安装的应用软件处于这种状态。
- Restricted:不仅应用软件无法访问通讯录数据,就连用户也无法通过设置修改授权状态。该状态是由于其他限制,也就是家长控制(parental control)所导致。
- Denied:表示用户不允许访问通讯录数据。只有用户才能够修改该状态。
- Authorized:这是每个应用软件期望得到的状态。在该状态下,应用软件可以随意访问通讯录数据库,使用通讯录数据执行操作。
我们其实只需要判断授权状态是否为 CNAuthorizationStatusAuthorized 即可,如果是表示授权状态成功,否则失败,不允许访问通讯录。
CNContactStore (相当于ABAddressBook)类以编程方式展示了联系人数据库,并且提供了许多实现不同任务的方法,例如获取,保存或者更新记录,权限检查和权限请求,很多很多。
CNContact类(相当于ABRecordRef)展示一个单独的联系人记录,但是记住这个类的特性是不可变的。如果你想创建一个新的联系人记录或者更新一个已存在的联系人记录,你必须使用CNMutableContact类。
需要注意的是在于Contacts框架打交道的时候,特别是获取联系人信息时,你应该始终在后台线程中运行这些任务。因为如果一个联系人信息获取任务花去了太多时间而且在主线程运行,那么你的应用有可能无响应,然后最终导致非常糟糕的交互体验。
于此同时在导入联系人信息到APP时,很少用到所有的联系人的属性信息。在所有的Contacts 框架要搜索的数据源中获取所有联系人数据的操作,被证明是一个非常耗资源的进程,所以应该避免检索所以联系人的属性信息,而是只检索需要的一部分属性信息,这个是在Contacts框架提供了的。例如,你可以只是请求名或姓,电话等,这样可以通过排除不需要的那些数据来节约很多资源。
查询联系人代码示例:
/** 查看联系人 */
- (void)readContact {
if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] != CNAuthorizationStatusAuthorized) return;//授权失败直接返回 //创建通讯录对象
CNContactStore *store = [[CNContactStore alloc] init]; // 创建获取通信录的请求对象
//拿到所有打算获取的属性对应的key(这里仅仅指定需要获取的数据,节约资源)
//我们这里仅仅作为示例,所以获取了所有的信息数据
NSArray *typeArray = @[CNContactGivenNameKey,CNContactFamilyNameKey,CNContactPhoneNumbersKey,CNContactEmailAddressesKey,CNContactBirthdayKey,CNContactDepartmentNameKey];
//创建CNContactFetchRequest对象
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:typeArray]; //遍历所有的联系人
[store enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) { //名字
NSString *firstName = contact.givenName;
//姓氏
NSString *lastName = contact.familyName;
NSLog(@"%@ -- %@", firstName, lastName);
//获取电话信息
NSArray *phones = contact.phoneNumbers;
for (int i = ; i<phones.count; i++) { CNLabeledValue *phone = phones[i]; //获取电话号码的KEY
NSString *label = phone.label; //获取电话号码
CNPhoneNumber *phoneNum = phone.value;
NSString *num = phoneNum.stringValue;
NSLog(@"name= %@ -- num = %@", label, num);
}
}]; }
插入联系人示例:
/**
* 添加联系人
*/
- (IBAction)addContact {
//1、联系人对象:CNContact
//这个对象是用来配置联系人信息的,有可变的CNMutaleContact和CNContact,区别用来读取和创建联系人。CNContact对象中有许多属性,对应联系人的一些信息。
//首先,创建CNMutableContact对象:
CNMutableContact *contact = [[CNMutableContact alloc]init];
//设置联系人数据
[self setupContact:contact];
//2、创建添加联系人请求:CNSaveRequest
//CNSaveRequest是用于存储联系人的请求类,通过这个类,我们可以创建批量添加、修改或者删除联系人的请求,例如添加上面我们创建的联系人对象:
//初始化方法
CNSaveRequest * saveRequest = [[CNSaveRequest alloc] init];
//添加联系人
[saveRequest addContact:contact toContainerWithIdentifier:nil];
//3 进行联系人的写入操作:CNContactStore
//CNContactStore是一个用于存取联系人的上下文桥梁,现在,把我们创建的添加联系人的请求写入:
CNContactStore * store = [[CNContactStore alloc]init];
[store executeSaveRequest:saveRequest error:nil];
} /** 设置联系人信息 */
- (void)setupContact:(CNMutableContact *)contact{
//设置联系人头像:
contact.imageData = UIImagePNGRepresentation([UIImage imageNamed:@"tour"]);
//设置联系人姓名:
//设置名字
contact.givenName = @"xiao";
//设置姓氏
contact.familyName = @"zhang";
//设置联系人邮箱(这里需要注意,emailAddresses属性是一个数组,数组中是才CNLabeledValue对象)
CNLabeledValue *homeEmail = [CNLabeledValue labeledValueWithLabel:CNLabelHome value:@"3242523553@qq.com"];
CNLabeledValue *workEmail =[CNLabeledValue labeledValueWithLabel:CNLabelWork value:@"324266653@qq.com"];
contact.emailAddresses = @[homeEmail,workEmail];
//设置联系人电话(和邮箱类似)
CNLabeledValue *mianPhone = [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMain value:[CNPhoneNumber phoneNumberWithStringValue:@""]];
CNLabeledValue *homePhone = [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberHomeFax value:[CNPhoneNumber phoneNumberWithStringValue:@""]];
contact.phoneNumbers = @[mianPhone, homePhone];
//设置联系人地址
CNMutablePostalAddress * homeAdress = [[CNMutablePostalAddress alloc]init];
homeAdress.street = @"大雁塔";
homeAdress.city = @"西安";
homeAdress.state = @"中国";
homeAdress.postalCode = @"xxxxx";
contact.postalAddresses = @[[CNLabeledValue labeledValueWithLabel:CNLabelHome value:homeAdress]];
//设置联系人生日
NSDateComponents * birthday = [[NSDateComponents alloc] init];
birthday.day=;
birthday.month=;
birthday.year=;
contact.birthday=birthday;
}
ContactsUI.frame框架
//打开通讯录
- (IBAction)openContact {
//初始化ContactPickerViewController
CNContactPickerViewController *pickVc = [[CNContactPickerViewController alloc] init];
//成为自己的代理
pickVc.delegate = self;
//跳转控制器
[self presentViewController:pickVc animated:YES completion:nil];
} #pragma mark - CNContactPickerDelegate
// 点击cancle按钮时候就会调用
- (void)contactPickerDidCancel:(CNContactPickerViewController *)picker{
NSLog(@"%s", __func__);
[picker dismissViewControllerAnimated:YES completion:nil];
} // 选中某一个联系人就会调用
//注意:只要实现了这个方法, 就不会进行下一步操作(进入详情), iOS9的做法是默认返回NO
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact{
NSLog(@"%s", __func__);
//姓氏
NSString *firstName = contact.familyName;
//名字
NSString *lastName = contact.givenName;
NSLog(@"%@---%@", firstName, lastName);
//电话信息
NSArray *phones = contact.phoneNumbers;
for (CNLabeledValue *phone in phones) {
//电话名称
NSString *name = phone.label;
//电话号码详情
CNPhoneNumber *phoneNum = phone.value;
NSLog(@"name = %@, phoneNum = %@", name, phoneNum.stringValue);
}
} // 选中某一个联系人的某一个属性时就会调用
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty{
NSLog(@"%s", __func__);
}