#import "ViewController.h"
#import <AddressBookUI/AddressBookUI.h>
#import <AddressBook/AddressBook.h>
@interface ViewController ()<ABPeoplePickerNavigationControllerDelegate>
@property (nonatomic, strong) ABPeoplePickerNavigationController * peoplePicker;
@property (nonatomic, strong) UILabel * nameLabel;
@property (nonatomic, strong) UILabel * phoLabel;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self createLabel];
[self createButton];
}
-(void)createLabel{
UILabel * nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 300, 100)];
nameLabel.backgroundColor = [UIColor lightGrayColor];
self.nameLabel = nameLabel;
[self.view addSubview:nameLabel];
UILabel * phoLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 150, 300, 100)];
phoLabel.backgroundColor = [UIColor lightGrayColor];
self.phoLabel = phoLabel;
[self.view addSubview:phoLabel];
}
-(void)createButton{
UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(0, 0, 200, 100);
btn.center = self.view.center;
btn.backgroundColor = [UIColor blueColor];
[btn setTitle:@"按钮" forState:UIControlStateNormal];
[self.view addSubview:btn];
[btn addTarget:self action:@selector(showPhoneBook) forControlEvents:UIControlEventTouchUpInside];
}
//调取电话本
-(void)showPhoneBook{
//1、授权
[self accessTheAddress];
//2、创建控制器
ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
peoplePicker.peoplePickerDelegate = self;
self.peoplePicker = peoplePicker;
//3-1、在iOS8之后,需要添加nav.predicateForSelectionOfPerson = [NSPredicate predicateWithValue:false];这一段代码,
//3-2、否则选择联系人之后会直接dismiss,不能进入详情选择电话。
if([[UIDevice currentDevice].systemVersion floatValue] >= 8.0){
peoplePicker.predicateForSelectionOfPerson = [NSPredicate predicateWithValue:false];
}
//4、推入控制器
[self presentViewController:peoplePicker animated:YES completion:nil];
}
//由于在ios6以后对用户信息提供了安全的保护,在获取前必须要通过用户的同意才行
//但ios8之后又不用去主动进行用户授权
- (void)accessTheAddress
{
ABAddressBookRef addressBook = nil;
float version = [[UIDevice currentDevice].systemVersion floatValue];
if ( version >= 6.0 && version <= 8.0 ) {
addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
//等待同意后向下执行
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
dispatch_semaphore_signal(sema);
NSLog(@"这里是用户选择是否允许后的执行代码");
if (granted) {
NSLog(@"用户进行了授权");
}
else{
NSLog(@"用户为进行授权");
}
});
}
else{
addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
}
}
#pragma mark - ABPeoplePickerNavigationControllerDelegate
//ios8及之后调用的方法
//ios8选中某一个联系人的某一个属性时就会调用
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
//取得联系人姓名
NSString * name = (__bridge NSString *)ABRecordCopyCompositeName(person);
NSLog(@"name = %@",name);
NSString *firstName = (__bridge NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSLog(@"firstName = %@",firstName);
NSString *lastName = (__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
NSLog(@"lastName = %@",lastName);
//取得联系人公司
NSString *company = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonOrganizationProperty));
NSLog(@"company = %@",company);
//获取联系人的电话个数
ABMutableMultiValueRef phoneMulti = ABRecordCopyValue(person, kABPersonPhoneProperty);
long count = ABMultiValueGetCount(phoneMulti);
NSLog(@"count = %ld",count);
//取得联系人电话号码
NSString *phone = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonPhoneProperty));
NSLog(@"phone = %@",phone);
long index = ABMultiValueGetIndexForIdentifier((__bridge ABMultiValueRef)(phone), identifier);
NSLog(@"index = %ld",index);
if (index<0) {
//index出现 -1 情况 提示 系统通讯录有问题
NSLog(@"获取手机号失败,请手动输入");
return;
}
//获得选中的电话号码
NSString *phoneNumber = (__bridge NSString *)ABMultiValueCopyValueAtIndex((__bridge ABMultiValueRef)(phone), index);
NSLog(@"phoneNumber = %@",phoneNumber);
//显示联系人信息
self.nameLabel.text = name;
self.phoLabel.text = phoneNumber;
}
// ios8选中一个联系人就会调用 实现这个方法之后,控制器不会进入到下一层(详情),直接dismiss
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person NS_AVAILABLE_IOS(8_0){
/**
* if([[UIDevice currentDevice].systemVersion floatValue] >= 8.0){
* peoplePicker.predicateForSelectionOfPerson = [NSPredicate predicateWithValue:false];
* }
* 如果有上面代码,就不会来到这个代理方法,联系人详情页可正常显示。
* for
*/
// ABPersonViewController *personViewController = [[ABPersonViewController alloc] init];
// personViewController.displayedPerson = person;
// [peoplePicker pushViewController:personViewController animated:YES];
}
//点击取消的代理方法
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
peoplePicker.peoplePickerDelegate = nil;
[peoplePicker dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - ios8之前调用的方法
//ios8之前调用的方法
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person NS_DEPRECATED_IOS(2_0, 8_0){
return YES;
}
//ios8之前调用的方法
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier NS_DEPRECATED_IOS(2_0, 8_0){
ABMultiValueRef phone = ABRecordCopyValue(person, kABPersonPhoneProperty);
long index = ABMultiValueGetIndexForIdentifier(phone,identifier);
NSString *phoneNO = (__bridge NSString *)ABMultiValueCopyValueAtIndex(phone, index);
phoneNO = [phoneNO stringByReplacingOccurrencesOfString:@"-" withString:@""];
NSLog(@"%@", phoneNO);
if (phone && phoneNO.length == 11) {
[peoplePicker dismissViewControllerAnimated:YES completion:nil];
return NO;
}else{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"错误提示" message:@"请选择正确手机号" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alertView show];
}
return YES;
}
// 正则判断从电话本调取的手机号
- (NSString *)isMobileNumber:(NSString *)mobileNum
{
NSString * MOBILE = @"^(?:\\+?\\d*?\\s*)?(\\d{3})-?(\\d{4})-?(\\d{4})$";
NSRegularExpression * regex = [NSRegularExpression regularExpressionWithPattern:MOBILE options:NSRegularExpressionCaseInsensitive error:nil];
NSArray * matches = [regex matchesInString:mobileNum options:0 range:NSMakeRange(0, [mobileNum length])];
NSString * grop = nil;
NSString * grop1 = nil;
NSString * grop2 = nil;
NSString * grop3 = nil;
for (NSTextCheckingResult * match in matches) {
grop1 = [mobileNum substringWithRange:[match rangeAtIndex:1]];
grop2 = [mobileNum substringWithRange:[match rangeAtIndex:2]];
grop3 = [mobileNum substringWithRange:[match rangeAtIndex:3]];
}
grop = [[grop1 stringByAppendingString:grop2] stringByAppendingString:grop3];
NSLog(@"%@",grop);
if (!grop) {
return @"无";
}else{
return grop;
}
}
/**
*
ABPeoplePickerNavigationController也有对应的代理方法,可以实现用户对通讯录的操作。要注意的时,ios7和ios8使用的代理方法是有区别的。ios8下会有意想不到的bug,到目前为止遇到了两个:
第一个bug:进入到信息人详情页后,会突然dismiss
解决办法是:
在实例化ABPeoplePickerNavigationController时,加上下面的代码
if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0){
//点击联系人跳转到联系人详情界面
peoplePicker.predicateForSelectionOfPerson = [NSPredicate predicateWithValue:FALSE];//防止进入详情页的时候突然dismiss,ios8的bug
}
第二个bug:点击联系电话时,跳转到了拨打电话的界面
bug原因是:ios7和ios8下要实现的代理方法是不同的
解决办法是:stackoverflow网站的建议如下:
意思就是如果是ios8,就是在ios的代理方法中调用ios7下的代理方法
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];
}
注意:如果Xcode提示:plugin com.apple.MobileAddressBook.ContactsViewService invalidated,只要把APPeoplePickerViewController设置为属性即可。
@property (nonatomic, strong) ABPeoplePickerNavigationController * peoplePicker;
* for
*/
@end
参考文章:
1、IOS 如何实现点击按钮弹出通讯录 再点一个人返回此的号码? | iOS开发 - CocoaChina CocoaChina_让移动开发更简单
2、iOS读取通讯录功能 - iOS专栏 - 博客频道 - youkuaiyun.com
3、ABPeoplePickerNavigationController - 标哥 - 博客频道 - youkuaiyun.com
4、iOS:ABPeoplePickerNavigationController系统通讯录使用 - 推酷
5、不同iOS系统版本下ABPeoplePickerNavigationController和ABAddressBook访问系统通讯录的区别 / 蓝讯
8、iOS获取手机通讯录(两种框架详解) - OPEN 开发经验库
9、iOS系统通讯录授权,获取,修改,创建联系人 - sw_gegewu的博客 - 博客频道 - youkuaiyun.com
10、ios9.0 ContactsUI获取通讯录联系人信息 | 程序员的资料库