AddressBook/AddressBookUI
概述
在iOS中,有2个框架可以访问用户的通讯录。从iOS6开始,需要得到用户的授权才能访问通讯录,因此在使用之前,需要检查用户是否已经授权ABAddressBookGetAuthorizationStatus()
授权状态
kABAuthorizationStatusNotDetermined 用户还没有决定是否授权你的程序进行访问
kABAuthorizationStatusRestricted iOS设备上的家长控制或其它一些许可配置阻止程序与通讯录数据库进行交互
kABAuthorizationStatusDenied 用户明确的拒绝了你的程序对通讯录的访问
kABAuthorizationStatusAuthorized 用户已经授权给你的程序对通讯录进行访问
AddressBook
。纯C语言的API,仅仅是获得联系人数据
。没有提供UI界面展示,需要自己搭建联系人展示界面
。里面的数据类型大部分基于Core Foundation框架
申请访问通讯录
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL); //创建通讯录对象 ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error){ if (granted) { NSLog(@"授权成功!"); } else { NSLog(@"授权失败!"); } }); //请求访问,granted为YES则请求成功 CFRelease(addressBook); // 释放资源--CF框架需要手动释放
联系人属性
联系人属性包括以下类型:
简单属性:姓、名等
多重属性:电话号码、电子邮件等
组合属性:地址等
(所有的属性常量值都定义在了ABPerson.h头文件中)
一个联系人就是一个ABRecordRef,每个联系人都有自己的属性,比如名字、电话、邮件等
简单属性
使用ABRecordCopyValue(ABRecordRef实例,属性关键字)可以从实例对象中获得对应关键字的属性值
ABPersonCopyLocalizedPropertyName函数可以根据指定的关键字获取对应的标签文本
// 获取所有联系人记录 CFArrayRef array = ABAddressBookCopyArrayOfAllPeople(addressBook); NSInteger count = CFArrayGetCount(array); for (NSInteger i = 0; i < count; ++i) { // 取出一条记录 ABRecordRef person = CFArrayGetValueAtIndex(array, i); // 取出个人记录中的详细信息 // 名 CFStringRef firstNameLabel = ABPersonCopyLocalizedPropertyName(kABPersonFirstNameProperty); CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty); CFStringRef lastNameLabel = ABPersonCopyLocalizedPropertyName(kABPersonLastNameProperty); // 姓 CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty); NSLog(@"%@ %@ - %@ %@", lastNameLabel, lastName, firstNameLabel, firstName); }
多重属性
联系人的有些属性值就没这么简单,一个属性可能会包含多个值
比如邮箱,分为工作邮箱、住宅邮箱、其他邮箱等
比如电话,分为工作电话、住宅电话、其他电话等
如果是复杂属性,那么ABRecordCopyValue函数返回的就是ABMultiValueRef类型的数据,例如邮箱或者电话
// 取电话号码 ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty); // 取记录数量 NSInteger phoneCount = ABMultiValueGetCount(phones); // 遍历所有的电话号码 for (NSInteger i = 0; i < phoneCount; i++) { // 电话标签 CFStringRef phoneLabel = ABMultiValueCopyLabelAtIndex(phones, i); // 本地化电话标签 CFStringRef phoneLocalLabel = ABAddressBookCopyLocalizedLabel(phoneLabel); // 电话号码 CFStringRef phoneNumber = ABMultiValueCopyValueAtIndex(phones, i);
}
添加联系人
>通过ABPersonCreate函数创建一个新的联系人(返回ABRecordRef)
>通过ABRecordSetValue函数设置联系人的属性
>通过ABAddressBookAddRecord函数将联系人添加到通讯录数据库中
>通过ABAddressBookSave函数保存刚才所作的修改
可以通过ABAddressBookHasUnsavedChanges函数判断是否有未保存的修改
当决定是否更改通讯录数据库后,你可以分别使用 AbAddressBookSave 或 ABAddressBookRevert 方式来保存或放弃更改
添加群组
>通过ABPersonCreate函数创建一个新的组(返回ABRecordRef)
>通过ABRecordSetValue函数设置组名
>通过ABAddressBookAddRecord函数将组添加到通讯录数据库中
>通过ABAddressBookSave函数保存刚才所作的修改
操作联系人头像
ABPersonHasImageData
判断通讯录中的联系人是否有图片
ABPersonCopyImageData
取得图片数据(假如有的话)
ABPersonSetImageData
设置联系人的图片数据
AddressBookUI.framework
。提供了联系人列表界面、联系人详情界面、添加联系人界面等
。一般用于选择联系人
通过ABPeoplePickerNavigationController操作,简单方便,无需自己搭建界面;
ABPeoplePickerNavigationController的代理属性为:peoplePickerDelegate(注:非常见的delegate)
AddressBookUI的协议在iOS8时有修改,协议方法有修改:
// 在iOS7时 点击cancle按钮时候就会调用 - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker { NSLog(@"%s", __func__); // 关闭通讯录 [peoplePicker dismissViewControllerAnimated:YES completion:nil]; } // 在iOS7时 , 选中某一个联系人就会调用 // 返回一个BOOL值, 如果返回NO, 代表不会进入下一层(详情), 如果返回YES,代表会进入下一层 - (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person { NSLog(@"%s", __func__); /* //取出当前联系人的的电话信息 // 获取练习人得姓名 CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty); CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty); NSLog(@"%@ %@", firstName, lastName); // 获取联系人的电话 // 从联系人中获取到得电话是所有的电话 ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty); // 获取当前联系人总共有多少种电话 CFIndex phoneCount = ABMultiValueGetCount(phones); for (int i = 0; i < phoneCount; i++) { CFStringRef name = ABMultiValueCopyLabelAtIndex(phones, i); // 从所有的电话中取出指定的电话 CFStringRef value = ABMultiValueCopyValueAtIndex(phones, i); NSLog(@"name = %@ value = %@", name, value); } */ return YES; } // 在iOS7时 , 选中某一个联系人的某一个属性时就会调用 // 返回一个BOOL值, 如果返回NO, 代表不会进行下一步操作(打电话, 打开日历....), 如果返回YES,代表会进行下一步操作 - (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier { NSLog(@"%s", __func__); return YES; } #pragma mark - iOS8 // 选中某一个联系人就会调用 #warning 只要实现了这个方法, 就不会进行下一步操作(进入详情), iOS8的做法是默认返回NO - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person { NSLog(@"%s", __func__); } // 选中某一个联系人的某一个属性时就会调用 - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person
property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier { NSLog(@"%s", __func__); }
第三方框架:RHAddressBook
不论是AddressBook还是AddressBookUI,在操作联系人属性时都只能用CF代码,不方便;
RHAddressBook可以以纯OC方式操作,提供了很大的便利
- (void)viewDidLoad { [super viewDidLoad]; // 1.创建通讯录 self.ab = [[RHAddressBook alloc] init]; // 2.判断是否授权 if ([RHAddressBook authorizationStatus] == RHAuthorizationStatusNotDetermined){ // 3.主动请求授权 [self.ab requestAuthorizationWithCompletion:^(bool granted, NSError *error) { if (granted) { NSLog(@"授权成功"); }else { NSLog(@"授权失败"); } }]; } } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSArray *allPeople = [self.ab people]; for (RHPerson *person in allPeople) { NSLog(@"%@", person); } }