abpeoplepickernavigationviewcontroller 是私有api吗

苹果的通讯录功能在iOS7,iOS8,iOS9 都有着一定的不同,iOS7和8用的是&&AddressBookUI/AddressBookUI.h& ,但是两个系统版本的代理方法有一些变化,有些代理方法都标注了&NS_DEPRECATED_IOS(2_0, 8_0) 并推荐了另一个代理方法与之对应。 &而iOS8到iOS9则是直接弃用了&AddressBookUI/AddressBookUI.h&取而代之的是&ContactsUI/ContactsUI.h&,后者是OC调用,据说当时苹果宣布弃用AddressBookUI还引来了阵阵欢呼。这也就是在使用通讯录功能时得考虑版本各种判断,我也就是工作中遇到了这种坑,然后就顺手兼容封装了一下。希望能解决这个问题。
我觉得通讯录这里的类结构没必要像SDWebImage或是Core Location这样列出来详细去说。大家用到通讯录无外乎就三个功能:
1.点击弹出通讯录页面,选择了一个联系人的电话后直接将信息填到页面输入框内。
2.遍历所有的通讯录数据统一做批量操作,搭建新页面或直接上传。
3.给通讯录写入一条信息。
这里会先对比一下iOS789的写法,最后奉上demo(一个封装后的库,提供了非常便利的api)。不关心内部实现的朋友可以直接拉到demo部分。
一、首先是获取通讯录的权限
iOS7和8保持一致
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (status == kABAuthorizationStatusNotDetermined) {
NSLog(@"还没问");
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error){
if(granted){
NSLog(@"点击同意");
NSLog(@"点击拒绝");
}else if (status == kABAuthorizationStatusAuthorized){
NSLog(@"已经授权");
[self loadPerson];
NSLog(@"没有授权");
// 弹窗提示去获取权限
iOS9及以后调用方法改成
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
if (status == CNAuthorizationStatusNotDetermined) {
[[[CNContactStore alloc]init] requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
NSLog(@"还没问");
if(granted){
NSLog(@"点击了同意");
[self loadPerson];
NSLog(@"点击了拒绝");
}else if (status == CNAuthorizationStatusAuthorized){
NSLog(@已经授权");
NSLog(@"没有授权");
二、弹出通讯录选择界面
iOS7的写法如下,代理方法的返回值大多是BOOL类型。
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
return YES;
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
ABMultiValueRef phone = ABRecordCopyValue(person, kABPersonPhoneProperty);
long index = ABMultiValueGetIndexForIdentifier(phone,identifier);
NSString *phoneNO = (__bridge NSString *)ABMultiValueCopyValueAtIndex(phone, index);
CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastname = (__bridge_transfer NSString *)(lastName);
NSString *firstname = (__bridge_transfer NSString *)(firstName);
if (phone) {
[peoplePicker dismissViewControllerAnimated:YES completion:nil];
return NO;
return YES;
iOS8的代理方法换了,改成了下面两个,但是方法内部的取值基本相同
// 点击了通讯录名字就会退出
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)
// 点击了名字里面的电话或邮箱才会退出
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)
至于会调用哪一个方法,可以根据实际需要去选择,在弹出界面的方法中predicateForSelectionOfPerson 这个属性传false就是调用下面的。
ABPeoplePickerNavigationController *pickervc = [[ABPeoplePickerNavigationController alloc] init];
pickervc.predicateForSelectionOfPerson = [NSPredicate predicateWithValue:false];
pickervc.peoplePickerDelegate =
[target presentViewController:pickervc animated:YES completion:nil];
iOS9系统下的弹出选择器方法 和 代理方法如下
// 弹出选择器
- (void)presentPageOnTarget{
CNContactPickerViewController *contactVc = [[CNContactPickerViewController
alloc] init];
contactVc.delegate =
[target presentViewController:contactVc animated:YES completion:nil];
// 代理方法
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact
SXPersonInfoEntity *personEntity = [SXPersonInfoEntity new];
NSString *lastname = contact.familyN
NSString *firstname = contact.givenN
NSLog(@"%@ %@", lastname, firstname);
personEntity.lastname =
personEntity.firstname =
NSMutableString *fullname = [[NSString stringWithFormat:@"%@%@",lastname,firstname] mutableCopy];
[fullname replaceOccurrencesOfString:@"(null)" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, fullname.length)];
personEntity.fullname =
NSString *fullPhoneStr = [NSString string];
NSArray *phoneNums = contact.phoneN
for (CNLabeledValue *labeledValue in phoneNums) {
NSString *phoneLabel = labeledValue.
CNPhoneNumber *phoneNumer = labeledValue.
NSString *phoneValue = phoneNumer.stringV
NSLog(@"%@ %@", phoneLabel, phoneValue);
if (phoneValue.length & 0) {
fullPhoneStr = [fullPhoneStr stringByAppendingString:phoneValue];
fullPhoneStr = [fullPhoneStr stringByAppendingString:@","];
if (fullPhoneStr.length & 1) {
personEntity.phoneNumber = [fullPhoneStr substringToIndex:fullPhoneStr.length - 1];
self.chooseAction(personEntity);
这个是点击了名字就直接回调的方法,如果希望点击了属性再回调,则需要加上这一行
contactVc.predicateForSelectionOfContact = [NSPredicate predicateWithValue:false];
// 代理方法调用
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty
三、获取全部通讯录信息
关于批量获取所有通讯录信息的方法有点冗长,这里就不一一贴了,只贴下iOS9的写法,iOS7和8的代码demo里都有。
- (void)printAllPerson
CNContactStore *contactStore = [[CNContactStore alloc] init];
NSArray *keys = @[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey];
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keys];
[contactStore enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
NSString *lastname = contact.familyN
NSString *firstname = contact.givenN
NSLog(@"%@ %@", lastname, firstname);
NSArray *phoneNums = contact.phoneN
for (CNLabeledValue *labeledValue in phoneNums) {
NSString *phoneLabel = labeledValue.
CNPhoneNumber *phoneNumer = labeledValue.
NSString *phoneValue = phoneNumer.stringV
NSLog(@"%@ %@", phoneLabel, phoneValue);
四、写入通讯录
因为写入的话这个功能有点重量级,写入的时候要写入,名字、电话、email、地址等等,这就会使得api过于复杂。暂时我见到过的做法大多都是如果用户给了通讯录权限 那就给你插入一条名字+电话,我做了只有这两个入参的api,当然使用时也完全可以扩展成更多参数的。
- (void)creatItemWithName:(NSString *)name phone:(NSString *)phone
if((name.length & 1)||(phone.length & 1)){
NSLog(@"输入属性不能为空");
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
ABRecordRef newRecord = ABPersonCreate();
ABRecordSetValue(newRecord, kABPersonFirstNameProperty, (__bridge CFTypeRef)name, &error);
ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(multi, (__bridge CFTypeRef)name, kABPersonPhoneMobileLabel, NULL);
ABRecordSetValue(newRecord, kABPersonPhoneProperty, multi, &error);
CFRelease(multi);
ABAddressBookAddRecord(addressBook, newRecord, &error);
ABAddressBookSave(addressBook, &error);
CFRelease(newRecord);
CFRelease(addressBook);
- (void)creatItemWithName:(NSString *)name phone:(NSString *)phone
// 创建对象
// 这个里面可以添加多个电话,email,地址等等。 感觉使用率不高,只提供了最常用的属性:姓名+电话,需要时可以自行扩展。
CNMutableContact * contact = [[CNMutableContact alloc]init];
contact.givenName = name?:@"defaultname";
CNLabeledValue *phoneNumber = [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMobile value:[CNPhoneNumber phoneNumberWithStringValue:phone?:@"10086"]];
contact.phoneNumbers = @[phoneNumber];
// 把对象加到请求中
CNSaveRequest * saveRequest = [[CNSaveRequest alloc]init];
[saveRequest addContact:contact toContainerWithIdentifier:nil];
// 执行请求
CNContactStore * store = [[CNContactStore alloc]init];
[store executeSaveRequest:saveRequest error:nil];
五、我的demo
因为不同版本用的类和枚举都不一样,所以我要设置一个统一的,并且在我的manager中处理各个版本间的判断。 最后开放出来统一的api,只要引入头文件SXAddressBookManager.h 就可以使用这些通用接口了。
①检查当前状态,有两种api&
- (void)checkStatus1
SXAddressBookAuthStatus status = [[SXAddressBookManager manager]getAuthStatus];
if (status == kSXAddressBookAuthStatusNotDetermined) {
[[SXAddressBookManager manager]askUserWithSuccess:^{
NSLog(@"点击同意");
} failure:^{
NSLog(@"点击拒绝");
}else if (status == kSXAddressBookAuthStatusAuthorized){
NSLog(@"已有权限");
NSLog(@"没有权限");
- (void)checkStatus2
[[SXAddressBookManager manager]checkStatusAndDoSomethingSuccess:^{
NSLog(@"已经有权限,做相关操作,可以做读取通讯录等操作");
} failure:^{
NSLog(@"未得到权限,做相关操作,可以做弹窗询问等操作");
②弹出选择窗口,点击回调选中的信息
- (void)touchesBegan:(NSSet&UITouch *& *)touches withEvent:(UIEvent *)event
[[SXAddressBookManager manager]presentPageOnTarget:self chooseAction:^(SXPersonInfoEntity *person) {
NSLog(@"%@---%@",person.fullname,person.phoneNumber);
③获得整个通讯录信息
self.personEntityArray = [[SXAddressBookManager manager]getPersonInfoArray];
④往通讯录写入一条信息
[[SXAddressBookManager manager]creatItemWithName:@"雷克萨斯-北京咨询电话" phone:@"010-"];
demo的地址是
这里写了我说的那三点常用,如果以后有一些刚需,会不断补充。 董铂然博客园。
阅读(...) 评论()ios - ABPeoplePickerNavigationController changes with iOS8? - Stack Overflow
to customize your list.
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.
J it only takes a minute:
Join the Stack Overflow community to:
Ask programming questions
Answer and help your peers
Get recognized for your expertise
Since I have updated XCode (6.0, 6A313) and my iOS (8.0, 12A365) on the iPhone to gm seeds, the ABPeoplePickerNavigationController code doesn't work like before.
iOS 7.1.2: If someone want to import a contact, the address book opens and you see the full list of contacts, after picking one, it opens detail view of an contact and than you can add the contact with a click of the phone number you want to import.
iOS 8.0: its everything similar but if you click on number of an contact it dial the phone number instead of importing it..
#pragma mark - AddressBook Delegate Methods
-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{
return YES;
-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
// Get the first and the last name. Actually, copy their values using the person object and the appropriate
// properties into two string variables equivalently.
// Watch out the ABRecordCopyValue method below. Also, notice that we cast to NSString *.
NSString *firstName = (__bridge NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = (__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
// Compose the full name.
NSString *fullName = @"";
// Before adding the first and the last name in the fullName string make sure that these values are filled in.
if (firstName != nil) {
fullName = [fullName stringByAppendingString:firstName];
if (lastName != nil) {
fullName = [fullName stringByAppendingString:@" "];
fullName = [fullName stringByAppendingString:lastName];
// Get the multivalue number property.
CFTypeRef multivalue = ABRecordCopyValue(person, property);
// Get the index of the selected number. Remember that the number multi-value property is being returned as an array.
CFIndex index = ABMultiValueGetIndexForIdentifier(multivalue, identifier);
// Copy the number value into a string.
NSString *number = (__bridge NSString *)ABMultiValueCopyValueAtIndex(multivalue, index);
nameTextField.text = fullN
numberTextField.text =
// Dismiss the contacts view controller.
[_addressBookController dismissViewControllerAnimated:YES completion:nil];
return NO;
// Implement this delegate method to make the Cancel button of the Address Book working.
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
[_addressBookController dismissViewControllerAnimated:YES completion:nil];
couldn't find any answer in iOS developer library of apple.
have somebody else a solution for it?
iOS 8 requires a new delegate method be implemented for this:
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {
Keep the old delegate method in place to support iOS 7 or earlier. What I do in my app is call the iOS 7 delegate method from the iOS 8 delegate method:
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {
[self peoplePickerNavigationController:peoplePicker shouldContinueAfterSelectingPerson:person property:property identifier:identifier];
If this delegate method isn't implemented in iOS 8, tapping the value causes the action. When implemented, the delegate is called instead with the selected value.
139k15176220
See also the delegate method, new with iOS8:
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)
[self selectedPerson:person];
That's what I wanted in my case.
This worked for me on both iOS 8 and iOS 7 and lower.
Note I am using this didSelectPerson:(ABRecordRef)person instead.
//Needed for iOS 8
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person
NSLog(@"Went here 1 ...");
[self peoplePickerNavigationController:peoplePicker shouldContinueAfterSelectingPerson:person];
//needed for iOS 7 and lower
- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person
NSLog(@"Went here 2 ...");
//add your logic here
8,59164888
protected by ♦
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10
on this site (the ).
Would you like to answer one of these
Not the answer you're looking for?
Browse other questions tagged
Stack Overflow works best with JavaScript enabledPages: 1/4
主题 : ABPeoplePickerNavigationController 通讯录问题
级别: 新手上路
可可豆: 201 CB
威望: 202 点
在线时间: 80(时)
发自: Web Page
来源于&&分类
ABPeoplePickerNavigationController 通讯录问题&&&
请问::我调用系统的通讯录控件  ABPeoplePickerNavigationController 后出来的标题是 All Contacts ,怎么才能改成中文的呢?info.plist 文件里Localization native development region 我已经设置成 zh_CN 了,为什么还是不行呢 ?我是在真机上测试的,真机环境都是中文的。。哪位朋友遇到过类似问题啊,希望指点一二~
级别: 骑士
可可豆: 1725 CB
威望: 1725 点
在线时间: 326(时)
发自: Web Page
直接打开模拟器中的通讯薄显示的是中文吗?
&I'm convinced that the only thing that kept me going was that I loved what I did.& - Steve Jobs
级别: 骑士
可可豆: 1859 CB
威望: 1859 点
在线时间: 134(时)
发自: Web Page
需要使用NSLocalizedString进行国际化,生成一个zh_CN的string文件
级别: 新手上路
可可豆: 201 CB
威望: 202 点
在线时间: 80(时)
发自: Web Page
回 1楼(r2007) 的帖子
直接打开模拟器中的通讯录是中文的。。
级别: 新手上路
可可豆: 201 CB
威望: 202 点
在线时间: 80(时)
发自: Web Page
回 2楼(小峰低调) 的帖子
需要手动进行国际化,不能吧。。那 string文件里应该怎么写呢?
级别: 骑士
可可豆: 1725 CB
威望: 1725 点
在线时间: 326(时)
发自: Web Page
同问,原生控件还需要自己定制国际化?
&I'm convinced that the only thing that kept me going was that I loved what I did.& - Steve Jobs
级别: 骑士
可可豆: 1859 CB
威望: 1859 点
在线时间: 134(时)
发自: Web Page
回 4楼(yepeiwen520) 的帖子
string文件是用终端的genstring命令编出来的
级别: 新手上路
可可豆: 201 CB
威望: 202 点
在线时间: 80(时)
发自: Web Page
回 6楼(小峰低调) 的帖子
哥啊&&怎么搞的&&能说说细节吗 ?
级别: 骑士
可可豆: 1859 CB
威望: 1859 点
在线时间: 134(时)
发自: Web Page
iPhone 中使用NSLocalizedString实现国际化   16:45:19|  分类: iPhone |字号 订阅一、获取系统所支持的国际化信息
在国际化之前,你可以在iphone中的”设置-&通用-&多语言环境-&语言”中来查看你的iphone支持哪些语言,当然也可以写 一段代码测试一下你的iphone都支持哪些语言.测试代码如下:NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSArray *languages = [defaults objectForKey:@&AppleLanguages&]; NSLog(@&%@&, languages);注:NSUserDefaults类用来取得用户人默认信息.二、在Xcode中建立多语言文档
1.在Resources分类下新建文档(右键/Add/New File…)
2.在模板对话框中选择Other,然后再选择Strings File
3.将文件保存名设置为Localizable.strings
4.在Localizable.strings 文件上按右键并选择 Get Info
5.点击信息界面的Make File Localizable,然后再将Tab标签切换到General
6.输入新的语言名称 zh 后按 Add,些时有English与zh两种语言,你还可以增加其它语言.三、在源代码中使用NSLocalizedString来引用国际化文件//括号里第一个参数是要显示的内容,与各Localizable.strings中的id对应//第二个是对第一个参数的注释,一般可以为空串[_alertView setTitle:NSLocalizedString(@&Submitted successfully&,@&&)];四、使用Terminal的genstrings命令进行生成资源文件
打开Terminal,然后cd到工程所在的目录,然后使用genstrings来生成自动从源代码中生成资源文件.
例如,项目的目录为:/user/project/test01,则命令如下:genstrings -o English.lproj&&./classes/*.mgenstrings -o zh.lproj&&./classes/*.m五、编辑各Localizable.strings文件
从第四步中得到了与代码对应的资源文件,最后我们需要对这些资源文件翻译成对应的语言就可以了.如在Localizable.strings(zh)中, 把等号后的文字进行编译成中文.&Submitted successfully& = &提交成功&重新编译整个工程后,就会在不同的语言环境下得到相应的语言显示.
级别: 骑士
可可豆: 1725 CB
威望: 1725 点
在线时间: 326(时)
发自: Web Page
[_alertView setTitle:NSLocalizedString(@&Submitted successfully&,@&&)];请问这句怎么添到ABPeoplePickerNavigationController中?
&I'm convinced that the only thing that kept me going was that I loved what I did.& - Steve Jobs
Pages: 1/4
关注本帖(如果有新回复会站内信通知您)
3*3+1 正确答案:10
发帖、回帖都会得到可观的积分奖励。
按"Ctrl+Enter"直接提交
关注CocoaChina
关注微信 每日推荐
扫一扫 浏览移动版10:38 提问
如何改变ABPeoplePickerNavigationController的UINavigationBar 颜色。
我用了ABAddressBookRef获取信息,用的还不错,不过我想改变ABPeoplePickerNavigationController的UINavigationBar的颜色。能实现吗?怎么实现?感谢帮忙。
按赞数排序
先设置颜色:
ABPeoplePickerNavigationController *objPeoplePicker = [[ABPeoplePickerNavigationController alloc] init];
[objPeoplePicker setPeoplePickerDelegate:self];
objPeoplePicker.topViewController.navigationController.navigationBar.tintColor = [UIColor colorWithRed:0.294 green:0.278 blue:0.247 alpha:1.0];
[self presentModalViewController:objPeoplePicker animated:YES];
改变UISearchBar的颜色
if( picker.searchDisplayController == nil )
NSLog(@"searchDisplayController is nil");
if( picker.topViewController.searchDisplayController == nil )
NSLog(@"topViewController.searchDisplayController is nil");
static BOOL foundSearchBar = NO;
- (void)findSearchBar:(UIView*)parent mark:(NSString*)mark {
for( UIView* v in [parent subviews] ) {
if( foundSearchBar )
NSLog(@"%@%@",mark,NSStringFromClass([v class]));
if( [v isKindOfClass:[UISearchBar class]] ) {
[(UISearchBar*)v
setTintColor:[UIColor blackColor]];
foundSearchBar = YES;
[self findSearchBar:v mark:[mark stringByAppendingString:@"& "]];
- (void)pickPerson:(BOOL)animated {
foundSearchBar = NO;
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
[[picker navigationBar] setTintColor:[UIColor blackColor]];
picker.peoplePickerDelegate =
picker.displayedProperties = [NSArray arrayWithObjects:
[NSNumber numberWithInt:kABPersonEmailProperty],
[self presentModalViewController:picker animated:animated];
[picker release];
[self findSearchBar:[picker view] mark:@"& "];
你可以设置一张你要的背景颜色的图片然后设置
[navigationController.navigationBar setBackgroundImage:
[UIImage imageNamed:@"navigationBar_bg.png"]forBarMetrics: UIBarMetricsDefault];
这个可以解决你的问题
53关注|244收录
517关注|579收录
657关注|1842收录
其他相似问题
相关参考资料}

我要回帖

更多关于 navigation 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信