iOS CNContactStore 与AddressBook

2018-12-03  本文已影响29人  rainbowboy

为了兼容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



解释说明

extern NSString *const contactNameKey;/*!通讯录人名key*/
extern NSString *const contactPhoneKey;/*!通讯录手机号key*/
<key>NSContactsUsageDescription</key>
<string>方便您填写联系人</string>

更新时间2018-12-4

上一篇 下一篇

猜你喜欢

热点阅读