美文网首页
iOS CNContactStore 与AddressBook

iOS CNContactStore 与AddressBook

作者: rainbowboy | 来源:发表于2018-12-03 19:17 被阅读29次

    为了兼容iOS9以前与iOS9以后用到的通讯录fromework,做了这个封装,方便调用CNContactStoreAddressBook

    需要导入的头文件

    //ios9之前导入的框架
    #import <AddressBook/AddressBook.h>
    #import <AddressBookUI/AddressBookUI.h>
    //ios9之后导入的框架
    #import <Contacts/Contacts.h>
    #import <ContactsUI/ContactsUI.h>
    

    封装的.h文件

    #import <Foundation/Foundation.h>
    @class UIViewController;
    
    extern NSString *const contactNameKey;/*!通讯录人名key*/
    extern NSString *const contactPhoneKey;/*!通讯录手机号key*/
    
    
    
    /**
     选择通讯录联系人之后的回调
    
     @param dic 回调返回的参数,key请参考contactNameKey,contactPhoneKey;
     */
    typedef void(^SelectContactBackBlock)(NSDictionary *dic);
    
    NS_ASSUME_NONNULL_BEGIN
    
    
    @interface RainContactKit : NSObject
    
    
    /**
     请求通讯录的授权信息,并且得到授权状态
     */
    - (BOOL)requestContactAuthorized;
    
    /**
     从一个VC打开通讯录选取功能
    
     @param fromVc 打开通讯录的VC
     @param contactBackBlock 选取某个通讯录人之后的回调
     */
    - (void)openContactFromVc:(UIViewController *)fromVc andCompletion:(SelectContactBackBlock) contactBackBlock;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    封装的.m文件

    #import "RainContactKit.h"
    //ios9之前导入的框架
    #import <AddressBook/AddressBook.h>
    #import <AddressBookUI/AddressBookUI.h>
    //ios9之后导入的框架
    #import <Contacts/Contacts.h>
    #import <ContactsUI/ContactsUI.h>
    
    NSString *const contactNameKey = @"rainContactNameKey";
    NSString *const contactPhoneKey = @"rainContactPhoneKey";
    static NSString *const alertMessage = @"您没有开启访问通讯录的权限,是否前往设置打开本程序的通讯录权限";
    
    
    
    @interface NSString (PhoneNumberTrim)
    
    /**
     过滤手机号里的特殊字符
     */
    - (NSString *)trimPhoneNumber;
    @end
    @implementation NSString (PhoneNumberTrim)
    
    - (NSString *)trimPhoneNumber {
        return [[[self stringByReplacingOccurrencesOfString:@"-" withString:@""]
                 stringByReplacingOccurrencesOfString:@" " withString:@""]
                stringByReplacingOccurrencesOfString:@"+86" withString:@""];
    }
    
    @end
    
    
    
    @interface RainContactKit ()<CNContactPickerDelegate,ABPeoplePickerNavigationControllerDelegate>
    @property (nonatomic,copy)SelectContactBackBlock contactBackBlock;
    @end
    
    
    @implementation RainContactKit
    
    - (BOOL)requestContactAuthorized {
        
        
        if (@available(iOS 9.0,*)) {
            return [self requestContactAuthorizedAfterSystemVersionNine];
        }else {
            return  [self requestContactAuthorizedBeforeSystemVersionNine];
            
        }
        
    
    }
    
    #pragma mark-  IOS9 及以后调用的方法
    /**
     IOS9 及以后调用的方法
     */
    - (BOOL)requestContactAuthorizedAfterSystemVersionNine {
        
        CNAuthorizationStatus contactStatus = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
        
        NSString *authorizedMsg = @"";
        
       __block BOOL isAuthorized = NO;
        
        switch (contactStatus) {
            case CNAuthorizationStatusNotDetermined: {
                authorizedMsg = @"用户未确定是否授权";
                CNContactStore *contactStore = [[CNContactStore alloc]init];
                
               dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
                
                [contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
                    
                    if (error) {
                        isAuthorized = NO;
    #ifdef DEBUG
                        NSLog(@"contact 授权 error:%@",error.description);
                        
    #endif
                    }else if(granted == NO){
                        isAuthorized = NO;
                    }else {
                        isAuthorized = YES;
                    }
                    
                    dispatch_semaphore_signal(semaphore);
                    
                }];
                
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
                
                
            }
                break;
            case CNAuthorizationStatusRestricted:
                authorizedMsg = @"iOS 设备上一些许可配置阻止程序与通讯录数据库进行交互";
                isAuthorized = NO;
                break;
            case CNAuthorizationStatusDenied:
                authorizedMsg = @"用户明确的拒绝了你的程序对通讯录的访问";
                isAuthorized = NO;
                break;
            case CNAuthorizationStatusAuthorized:
                authorizedMsg = @"用户已经授权给你的程序对通讯录进行访问";
                isAuthorized = YES;
                break;
            default:
                authorizedMsg = @"default 未知信息";
                isAuthorized = NO;
                break;
        }
    
    #ifdef DEBUG
        NSLog(@"在iOS 9及以上设备上,通讯录授权信息:%@ %d",authorizedMsg,isAuthorized);
    #endif
        
        return isAuthorized;
        
        
    }
    
    - (void)presentContactAfterSystemVersionNineFromVc:(UIViewController *)fromeVc {
        CNContactPickerViewController *contactVc = [[CNContactPickerViewController alloc]init];
        contactVc.delegate = self;
        [fromeVc presentViewController:contactVc animated:YES completion:nil];
        
    }
    
    #pragma mark- IOS9 以前调用的方法
    /**
     IOS9 以前调用的方法
     */
    - (BOOL)requestContactAuthorizedBeforeSystemVersionNine {
        ABAuthorizationStatus abStatus = ABAddressBookGetAuthorizationStatus();
        
        NSString *authorizedMsg = @"";
        
        __block BOOL isAuthorized = NO;
        
        switch (abStatus) {
            case kABAuthorizationStatusNotDetermined:{
                authorizedMsg = @"用户未确定是否授权";
                
                ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
                dispatch_semaphore_t semaphore2 = dispatch_semaphore_create(0);
                ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
                    
                    if (granted) {
                        isAuthorized = YES;
                    }else {
                        isAuthorized = NO;
                    }
                    dispatch_semaphore_signal(semaphore2);
                });
                
                dispatch_semaphore_wait(semaphore2, DISPATCH_TIME_FOREVER);
                
                CFRelease(addressBook);
            }
            break;
            case kABAuthorizationStatusRestricted:
                authorizedMsg = @"iOS 设备上一些许可配置阻止程序与通讯录数据库进行交互";
                isAuthorized = NO;
            break;
            case kABAuthorizationStatusDenied:
                authorizedMsg = @"用户明确的拒绝了你的程序对通讯录的访问";
                isAuthorized = NO;
            break;
            case kABAuthorizationStatusAuthorized:
                authorizedMsg = @"用户已经授权给你的程序对通讯录进行访问";
                isAuthorized = YES;
            break;
                
            default:
                authorizedMsg = @"default 未知信息";
                isAuthorized = NO;
                break;
        }
        
    #ifdef DEBUG
        NSLog(@"在iOS 9以下设备上,通讯录授权信息:%@ %d",authorizedMsg,isAuthorized);
    #endif
        
        return isAuthorized;
    }
    
    - (void)presentContactBeforeSystemVersionNineFromVc:(UIViewController *)fromeVc {
        ABPeoplePickerNavigationController *nav = [[ABPeoplePickerNavigationController alloc] init];
        nav.peoplePickerDelegate = self;
        [fromeVc presentViewController:nav animated:YES completion:nil];
        
    }
    
    #pragma mark- inner fucntion
    - (void)openContactFromVc:(UIViewController *)fromVc andCompletion:(SelectContactBackBlock) contactBackBlock {
        if ([self requestContactAuthorized]) {
            self.contactBackBlock =  contactBackBlock;
            
            if (@available(iOS 9.0,*)) {
                [self presentContactAfterSystemVersionNineFromVc:fromVc];
            }else {
                [self presentContactBeforeSystemVersionNineFromVc:fromVc];
            }
            
        }else {
            [self alertShow];
        }
    }
    
    
    - (void)alertShow {
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"温馨提示" message:alertMessage preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction *goAction = [UIAlertAction actionWithTitle:@"去设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            
            [[UIApplication sharedApplication]openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
        }];
        
        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
        [alertVC addAction:goAction];
        [alertVC addAction:cancelAction];
        
        [UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:alertVC animated:YES completion:nil];
        
    }
    
    
    
    #pragma mark- CNContactPickerDelegate
    
    - (void)contactPickerDidCancel:(CNContactPickerViewController *)picker {
        [picker dismissViewControllerAnimated:YES completion:nil];
    }
    
    
    - (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact {
        NSString *givenName = contact.givenName;
        NSString *familyName = contact.familyName;
        //全名
        NSMutableString *name = [NSMutableString string];
        if ([familyName length] > 0) { [name appendString:familyName]; }
        if ([givenName length] > 0) { [name appendString:givenName]; }
        
        NSString *phone = nil;
        
        NSArray *tmpArr = contact.phoneNumbers;
        for (CNLabeledValue *labelValue  in tmpArr) {
            CNPhoneNumber * number = labelValue.value;
            NSString *phoneNumber = number.stringValue;
            if (phoneNumber.length > 0) {
                phone = phoneNumber;
                break;
            }
        }
        
        phone = [phone trimPhoneNumber];
        
        NSMutableDictionary *contactDic = @{}.mutableCopy;
        [contactDic setValue:name.copy forKey:contactNameKey];
        [contactDic setValue:phone forKey:contactPhoneKey];
        
        [picker dismissViewControllerAnimated:YES completion:^{
            if (self.contactBackBlock) {
                self.contactBackBlock(contactDic.copy);
            }
        }];
        
    }
    
    #pragma mark ABPeoplePickerNavigationControllerDelegate
    
    //取消选择
    
    - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
    {
        
        [peoplePicker dismissViewControllerAnimated:YES completion:nil];
        
    }
    
    - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person
    
    {
        
        CFTypeRef abFirstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);//名
        
        CFTypeRef abLastName = ABRecordCopyValue(person, kABPersonLastNameProperty);//姓
        
        NSString *firstNameString = (__bridge NSString *)abFirstName;
        
        NSString *lastNameString = (__bridge NSString *)abLastName;
        
        //全名
        NSMutableString *name = [NSMutableString string];
        if ([lastNameString length] > 0) { [name appendString:lastNameString]; }
        if ([firstNameString length] > 0) { [name appendString:firstNameString]; }
        
        ABMultiValueRef phones= ABRecordCopyValue(person, kABPersonPhoneProperty);//手机号数组
        
        NSString *phone = nil;
        
        for (NSInteger j = 0; j < ABMultiValueGetCount(phones); j++) {
            
            /*因在ARC模式下,__bridge_transfer会自动对core指针release,同时得到cocoa对象指针,所以不用针对core指针做CFRelease()*/
            NSString *phoneNumber = (__bridge_transfer NSString *)(ABMultiValueCopyValueAtIndex(phones, j));
              if (phoneNumber.length > 0) {
                  phone = phoneNumber.copy;
                  break;
              }
            
        }
        
        phone = [phone trimPhoneNumber];
        
        CFRelease(phones);
        
        NSMutableDictionary *contactDic = @{}.mutableCopy;
        [contactDic setValue:name.copy forKey:contactNameKey];
        [contactDic setValue:phone forKey:contactPhoneKey];
        
        CFRelease(abFirstName);
        CFRelease(abLastName);
        
        [peoplePicker dismissViewControllerAnimated:YES completion:^{
            if (self.contactBackBlock) {
                self.contactBackBlock(contactDic.copy);
            }
        }];
        
    }
    
    
    @end
    
    
    
    

    解释说明

    • 在等待用户授权通讯录的地方使用了信号量semaphore,目的是为了同步到用户的授权状态再反馈给使用者
    • 点击获取的通讯录数据保存在字典里,使用的key分别为:
    extern NSString *const contactNameKey;/*!通讯录人名key*/
    extern NSString *const contactPhoneKey;/*!通讯录手机号key*/
    
    • 需要配置plist文件
    <key>NSContactsUsageDescription</key>
    <string>方便您填写联系人</string>
    

    更新时间2018-12-4

    相关文章

      网友评论

          本文标题:iOS CNContactStore 与AddressBook

          本文链接:https://www.haomeiwen.com/subject/gkducqtx.html