iOS开发:通讯录获取

本文介绍了一个iOS应用如何通过ABPeoplePickerNavigationController访问设备通讯录的方法,并详细解释了针对不同iOS版本(尤其是iOS 8及以后)所需的配置和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#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访问系统通讯录的区别 / 蓝讯

6、plugin com.apple.MobileAddressBook.ContactsViewService invalidated | iOS开发 - CocoaChina CocoaChina_让移动开发更简单

7、iOS通讯录开发 - 简书

8、iOS获取手机通讯录(两种框架详解) - OPEN 开发经验库

9、iOS系统通讯录授权,获取,修改,创建联系人 - sw_gegewu的博客 - 博客频道 - youkuaiyun.com

10、ios9.0 ContactsUI获取通讯录联系人信息 | 程序员的资料库



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值