在项目中有的地方会用到获取通讯里面的某个联系人的联系方式,这里我们稍微封装一下这个方法。
第一步:我们需要获取通讯录权限
在info.plist
文件中,添加 key : Privacy - Contacts Usage Description
,value:方便用户从通讯录选取要保存的号码
,如下图:
第二步:新建通讯录管理类
1、新建一个ContactManager
类
添加两个Block,用于回调权限和联系人号码
/**
* 通讯录权限Block
*
* @param isAuthorization 是否有权限; YES:有权限; NO:无权限
*/
typedef void(^AddressBookAuthorization)(BOOL isAuthorization);
/**
* 通讯录号码Block
*
* @param phoneNumber 号码
*/
typedef void(^AddressBookOfPhoneNumberBlock)(NSString *phoneNumber);
添加两个方法,用于获取权限和弹出通讯录列表
/**
* 模态弹出通讯录列表页
*
* @param addressBookOfPhoneNumber block
*/
- (void)presentAddressBookViewControllerWithPhoneNumber:(AddressBookOfPhoneNumberBlock)addressBookOfPhoneNumber;
/**
* 获取通讯录权限方法,可以单独使用
*
* @param contactAuthorization block
*/
- (void)getAddressBookAuthorization:(AddressBookAuthorization)contactAuthorization;
2、获取通讯录权限问题
获取通讯录权限的时候,判断系统版本,当veision >= 9.0
时,使用CNAuthorizationStatus
;否则使用ABAuthorizationStatus
。
- (void)getAddressBookAuthorization:(AddressBookAuthorization)contactAuthorization
{
NSString *version = [UIDevice currentDevice].systemVersion;
if (version.doubleValue >= 9.0) {
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
if (status == CNAuthorizationStatusNotDetermined) {
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
//第一次获取权限判断,点击 “不允许” 则 granted = NO;点击 “好” 则 granted = YES;
contactAuthorization(granted);
}];
} else if (status == CNAuthorizationStatusAuthorized) {//有权限
contactAuthorization(YES);
} else {//无权限
//NSLog(@"iOS 9 later 您未开启通讯录权限,请前往设置中心开启");
contactAuthorization(NO);
}
} else {
ABAddressBookRef bookref = ABAddressBookCreateWithOptions(NULL, NULL);
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(bookref, ^(bool granted, CFErrorRef error) {
contactAuthorization(granted);
});
}
if (status == kABAuthorizationStatusAuthorized) {
contactAuthorization(YES);
}else{
//NSLog(@"iOS 9 before 您未开启通讯录权限,请前往设置中心开启");
contactAuthorization(NO);
}
}
}
3、调起通讯录列表页
获取通讯录列表的时候,同样判断系统版本,当veision >= 9.0
时,使用CNContactPickerViewController
;否则使用ABPeoplePickerNavigationController
。
- (void)presentAddressBookViewControllerWithPhoneNumber:(AddressBookOfPhoneNumberBlock)addressBookOfPhoneNumber
{
[self getAddressBookAuthorization:^(BOOL isAuthorization) {
if (isAuthorization) {
[self presentABPeoplePickerOrCNContactPickerControllerWithPhoneNumber:addressBookOfPhoneNumber];
} else {
[self setContactAuthorization];
}
}];
}
- (void)presentABPeoplePickerOrCNContactPickerControllerWithPhoneNumber:(AddressBookOfPhoneNumberBlock)phoneNumberBlock
{
NSString *version = [UIDevice currentDevice].systemVersion;
//主线程刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
self.phoneNumberBlock = phoneNumberBlock;
if (version.doubleValue >= 9.0) {
//iOS 9 之后
CNContactPickerViewController *picker = [[CNContactPickerViewController alloc] init];
picker.delegate = self;
//picker.predicateForSelectionOfContact = [NSPredicate predicateWithFormat:@"emailAddresses.@count == 1"];
//picker.predicateForEnablingContact = [NSPredicate predicateWithFormat:@"emailAddresses.@count > 0"];
//picker.predicateForSelectionOfProperty = [NSPredicate predicateWithFormat:@"(key == 'emailAddresses') AND (value LIKE '*@mac.com')"];
picker.displayedPropertyKeys = @[CNContactPhoneNumbersKey];//只显示手机号
[KeyWidow.rootViewController presentViewController:picker animated:YES completion:nil];
} else {
//iOS 9 之前
ABPeoplePickerNavigationController *picker = [ABPeoplePickerNavigationController new];
picker.peoplePickerDelegate = self;
picker.displayedProperties = @[[NSNumber numberWithInt:kABPersonPhoneProperty]];
[KeyWidow.rootViewController presentViewController:picker animated:YES completion:nil];
}
});
}
4、代理方法回调
#pragma mark - CNContactPickerDelegate
- (void)contactPickerDidCancel:(CNContactPickerViewController *)picker
{
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty;
{
//注意:这里和displayedPropertyKeys属性设置相对应;只有 CNPhoneNumber 类型,如果添加别的类型,需要加类型判断,否则可能crash;例如:通讯录中的日期、邮箱...
CNPhoneNumber *phoneNumber = contactProperty.value;
NSString *phoneStr = phoneNumber.stringValue;
//回调block,把号码带回去
if (self.phoneNumberBlock) {
self.phoneNumberBlock(phoneStr);
}
}
#pragma mark - ABPeoplePickerNavigationControllerDelegate
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
[peoplePicker dismissViewControllerAnimated:YES completion:nil];
}
// 当用户选中某一个联系人时会执行该方法,并且选中联系人后会直接退出控制器
//- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person{
//
//}
// 当用户选中某一个联系人的某一个属性时会执行该方法,并且选中属性后会退出控制器
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
[self peoplePickerNavigationControllerDidCancel:peoplePicker];
ABMultiValueRef phones = ABRecordCopyValue(person, property);
CFIndex phoneCount = ABMultiValueGetCount(phones);
NSString *phoneValue = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phones, identifier);
//回调block,把号码带回去
if (self.phoneNumberBlock) {
self.phoneNumberBlock(phoneValue);
}
CFRelease(phones);
}
5、处理未开通通讯录权限情况
- (void)setContactAuthorization
{
//主线程刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:@"您没有开启通讯录权限,去开通权限!" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"不了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"这就去" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (@available(iOS 10.0, *)) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success) {
}];
} else {
// Fallback on earlier versions
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}
}];
[alert addAction:action1];
[alert addAction:action2];
[KeyWidow.rootViewController presentViewController:alert animated:YES completion:nil];
});
}
6、外部使用该封装类
//在外部使用该封装类,需要强引用,否则对象会提前释放后,导致block提前释放,以至于无法回调
@property (nonatomic, strong) ContactManager *contactManager;
self.contactManager = [[ContactManager alloc] init];
[self.contactManager presentAddressBookViewControllerWithPhoneNumber:^(NSString * _Nonnull phoneNumber) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@",phoneNumber);
});
}];
也可以使用单例写法,这时候需要在ContactManager
类中实现创建单例方法:
[[ContactManager shareAddressBook] presentAddressBookViewControllerWithPhoneNumber:^(NSString * _Nonnull phoneNumber) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@",phoneNumber);
});
}];
7、Demo下载地址:https://github.com/MichaelSSY/ContactManager。