有的时候我们需要获取用户的通讯录信息上传给服务器,对于iOS来说iOS9之前和之后有不同的方法用于获取通讯录信息。
在9之前的版本获取通讯录信息是通过ABAddressBookCopyArrayOfAllPeople
来获取所有联系人的信息的。所有的联系人信息被保存在一个数组里面,我们只需要遍历整个数组就可以获取我们想要的信息的。下面以获取所有联系人的姓名和电话号码和唯一识别码为例,提供一个简单的函数:
- (void)accessABAddressBook:(ABAddressBookRef)addressBookRef andResult:(void(^)(NSArray * models))completionHandler {
CFArrayRef arrayRef = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
for (int i = 0; i< CFArrayGetCount(arrayRef); i++) {
ABRecordRef people = CFArrayGetValueAtIndex(arrayRef, i);
NSString *identify = [NSString stringWithFormat:@"%d",ABRecordGetRecordID(people)];
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(people, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(people, kABPersonLastNameProperty));
NSString *name = [[NSString alloc] init];
if (firstName) {
name = [name stringByAppendingString:firstName];
}
if (lastName) {
name = [name stringByAppendingString:lastName];
}
ABMutableMultiValueRef phonesArray = ABRecordCopyValue(people, kABPersonPhoneProperty);
NSString *phoneNumber = @"";
for (int j = 0; j < ABMultiValueGetCount(phonesArray); j++) {
NSString *phone = (__bridge NSString *)(ABMultiValueCopyValueAtIndex(phonesArray, j));
if (phone) {
phone = [phone stringByAppendingString:@";"];
phoneNumber = [phoneNumber stringByAppendingString:phone];
}
}
if([phoneNumber isEqualToString:@""]) {
continue;
}
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:name,@"desc",phoneNumber,@"phoneNo",identify,@"deviceRecordId", nil];
[mutableArray addObject:dic];
}
completionHandler([mutableArray copy]);
}
在iOS9之后,苹果为方便获取通讯录提供了一套API,开发者可以通过CNContactStore
这个类获取需要的信息,这个类有个实例方法:enumerateContactsWithFetchRequest: error:usingBlock:
,每获取到一个联系人信息这个方法的回调函数就会执行一次。
This method waits until the enumeration is finished. If there are no results, the block is not called and the method returns YES.
This can be used to fetch all contacts without keeping all of them at once in memory because this is expensive.
上面是苹果开发文档里面的一段话,这个方法是同步的阻塞当前线程。所以我们可以很方便地获取所有的联系人信息。下面是在iOS9以后获取所有联系人的姓名电话号码和唯一身份识别码的一个方法:
- (void)accessContacts:(CNContactStore *)store andResult:(void(^)(NSArray * models))completionHandler{
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactGivenNameKey,CNContactFamilyNameKey,CNContactPhoneNumbersKey]];
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
[store enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
NSString *firstName = contact.familyName;
NSString *lastName = contact.givenName;
NSString *identify = contact.identifier;
NSString *name = [[NSString alloc] init];
if (firstName) {
name = [name stringByAppendingString:firstName];
}
if (lastName) {
name = [name stringByAppendingString:lastName];
}
NSString *phoneNumber = @"";
for (CNLabeledValue *phone in contact.phoneNumbers) {
NSString *number = phone.value.stringValue;
if (number) {
number = [number stringByAppendingString:@";"];
phoneNumber = [phoneNumber stringByAppendingString:number];
}
}
if ([phoneNumber isEqualToString:@""]) {
return ;
}
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:name,@"desc",phoneNumber,@"phoneNo",identify,@"deviceRecordId", nil];
[mutableArray addObject:dic];
}];
completionHandler([mutableArray copy]);
}
当然了事情到这里还没有结束,在获取通讯录之前我们需要用户授权。
获取用户授权主要思路是每次访问通讯录之前会检查授权情况如果已经授权直接访问通讯录,如果拒绝授权给出提示跳转应用设置页面引导用户打开授权,如果未授权则发起授权请求。问题比较简单就不加赘述,直接看代码:
- (void)accessAddressBookBefore9:(void(^)(NSArray * models))completionHandler {
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
ABAddressBookRef addressBookRef = ABAddressBookCreate();
if (status == kABAuthorizationStatusAuthorized) {
[self accessABAddressBook:addressBookRef andResult:completionHandler];
}else if (status == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
[self accessABAddressBook:addressBookRef andResult:completionHandler];
}else {
[self alert];
}
});
}else if (status == kABAuthorizationStatusDenied) {
[self alert];
}
if (addressBookRef) {
CFRelease(addressBookRef);
}
}
- (void)accessAddressBookLater9:(void(^)(NSArray * models))completionHandler {
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
CNContactStore *store = [[CNContactStore alloc] init];
if (status == CNAuthorizationStatusAuthorized) {
[self accessContacts:store andResult:completionHandler];
return;
}
if (status == CNAuthorizationStatusNotDetermined) {
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
[self accessContacts:store andResult:completionHandler];
}else {
[self alert];
}
}];
return;
}
if (status == CNAuthorizationStatusDenied) {
[self alert];
}
}
下面是封装的一个获取手机通讯录的类
#import
#import
#import
#import
#import "UIViewController+Tools.h"
#import "FWDefine.h"
@interface FWAddressBook : NSObject
- (void)accessAddressBook:(void(^)(NSArray *))completionHandler;
@end
#import "FWAddressBook.h"
@implementation FWAddressBook
- (void)accessAddressBook:(void(^)(NSArray * models))completionHandler {
if ([self terminate]) return;
if (Before9) {
[self accessAddressBookBefore9:completionHandler];
}else {
[self accessAddressBookLater9:completionHandler];
}
}
- (void)accessAddressBookLater9:(void(^)(NSArray * models))completionHandler {
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
CNContactStore *store = [[CNContactStore alloc] init];
if (status == CNAuthorizationStatusAuthorized) {
[self accessContacts:store andResult:completionHandler];
return;
}
if (status == CNAuthorizationStatusNotDetermined) {
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
[self accessContacts:store andResult:completionHandler];
}else {
[self alert];
}
}];
return;
}
if (status == CNAuthorizationStatusDenied) {
[self alert];
}
}
- (void)accessAddressBookBefore9:(void(^)(NSArray * models))completionHandler {
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
ABAddressBookRef addressBookRef = ABAddressBookCreate();
if (status == kABAuthorizationStatusAuthorized) {
[self accessABAddressBook:addressBookRef andResult:completionHandler];
}else if (status == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
[self accessABAddressBook:addressBookRef andResult:completionHandler];
}else {
[self alert];
}
});
}else if (status == kABAuthorizationStatusDenied) {
[self alert];
}
if (addressBookRef) {
CFRelease(addressBookRef);
}
}
- (void)accessABAddressBook:(ABAddressBookRef)addressBookRef andResult:(void(^)(NSArray * models))completionHandler {
CFArrayRef arrayRef = ABAddressBookCopyArrayOfAllPeople(addressBookRef);
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
for (int i = 0; i< CFArrayGetCount(arrayRef); i++) {
ABRecordRef people = CFArrayGetValueAtIndex(arrayRef, i);
NSString *identify = [NSString stringWithFormat:@"%d",ABRecordGetRecordID(people)];
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(people, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(people, kABPersonLastNameProperty));
NSString *name = [[NSString alloc] init];
if (firstName) {
name = [name stringByAppendingString:firstName];
}
if (lastName) {
name = [name stringByAppendingString:lastName];
}
ABMutableMultiValueRef phonesArray = ABRecordCopyValue(people, kABPersonPhoneProperty);
NSString *phoneNumber = @"";
for (int j = 0; j < ABMultiValueGetCount(phonesArray); j++) {
NSString *phone = (__bridge NSString *)(ABMultiValueCopyValueAtIndex(phonesArray, j));
if (phone) {
phone = [phone stringByAppendingString:@";"];
phoneNumber = [phoneNumber stringByAppendingString:phone];
}
}
if([phoneNumber isEqualToString:@""]) {
continue;
}
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:name,@"desc",phoneNumber,@"phoneNo",identify,@"deviceRecordId", nil];
[mutableArray addObject:dic];
}
completionHandler([mutableArray copy]);
}
- (void)accessContacts:(CNContactStore *)store andResult:(void(^)(NSArray * models))completionHandler{
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactGivenNameKey,CNContactFamilyNameKey,CNContactPhoneNumbersKey]];
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
[store enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
NSString *firstName = contact.familyName;
NSString *lastName = contact.givenName;
NSString *identify = contact.identifier;
NSString *name = [[NSString alloc] init];
if (firstName) {
name = [name stringByAppendingString:firstName];
}
if (lastName) {
name = [name stringByAppendingString:lastName];
}
NSString *phoneNumber = @"";
for (CNLabeledValue *phone in contact.phoneNumbers) {
NSString *number = phone.value.stringValue;
if (number) {
number = [number stringByAppendingString:@";"];
phoneNumber = [phoneNumber stringByAppendingString:number];
}
}
if ([phoneNumber isEqualToString:@""]) {
return ;
}
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:name,@"desc",phoneNumber,@"phoneNo",identify,@"deviceRecordId", nil];
[mutableArray addObject:dic];
}];
completionHandler([mutableArray copy]);
}
- (void)alert {
UIViewController *controller = [UIApplication sharedApplication].keyWindow.rootViewController;
[controller alertSure:^{
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
} message:@"为了成功贷款,请您前往设置页面允许应用访问通讯录"];
}
- (BOOL)terminate {
NSDate *date = [[NSUserDefaults standardUserDefaults] objectForKey:@"time"];
NSDate *currentDate = [NSDate date];
if (date) {
NSTimeInterval time = [currentDate timeIntervalSinceDate:date];
if (time < 24*60*60) return YES;
[self saveTime:currentDate];
}else {
[self saveTime:currentDate];
}
return NO;
}
- (void)saveTime:(NSDate *)time {
[[NSUserDefaults standardUserDefaults] setObject:time forKey:@"time"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
@end