关于通讯录
通讯录获取
通讯录简介
通讯录应用场景
- 最常见的是一些即时通讯APP, 关联联系人;
通讯录获取方案
AddressBookUI.framework 框架
提供了联系人列表界面、联系人详情界面、添加联系人界面等,一般用于选择联系人
AddressBook.framework 框架
- 纯C语言的API,仅仅是获得联系人数据
- 没有提供UI界面展示,需要自己搭建联系人展示界面
- 里面的数据类型大部分基于Core Foundation框架,使用起来极其蛋疼
- 从iOS6开始,需要得到用户的授权才能访问通讯录,因此在使用之前,需要检查用户是否已经授权
第三方框架 RHAddressBook
对AddressBook.framework框架的封装
iOS9.0最新通讯录获取框架 ContactsUI.framework: 方案1的替代品
特点: 面向对象, 使用简单. 有界面.
Contacts.framework: 方案2的替代品
特点: 面向对象, 使用简单. 无界面.
获取通讯录-AddressBookUI
实现步骤
- 创建选择联系人的控制器
- 设置代理(用来接收用户选择的联系人信息)
- 弹出联系人控制器
- 实现代理
- 在对应的代理方法中获取联系人信息
由于AddressBookUI已经是过期的,swift3.0不再支持,所以只能用OC描述上述步骤
#import "ViewController.h"
#import <AddressBookUI/AddressBookUI.h>
@interface ViewController ()<ABPeoplePickerNavigationControllerDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
ABPeoplePickerNavigationController *vc = [[ABPeoplePickerNavigationController alloc]init];
vc.peoplePickerDelegate = self;
[self presentViewController:vc animated:YES completion:nil];
}
//当通讯录退出时调用
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker {
NSLog(@"%s",__func__);
}
//选中联系人通讯录就退出
- (void)peoplePjiezickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person {
//ABRecordRef 表示一个联系人,一条记录
//从记录终取值,需要借助ABRecordCopyValue
//联系人里的记录分为2个类型:
//简单属性:如姓名
//复杂属性:如联系方式、邮件等,一般用 “标签” + “值”
NSLog(@"%s",__func__);
NSLog(@"选中联系人");
CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
NSString *fir = CFBridgingRelease(firstName);
NSString *las = CFBridgingRelease(lastName);
NSLog(@"%@---%@", fir, las);
ABMultiValueRef multi = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex count = ABMultiValueGetCount(multi);
for (int i = 0; i < count; i++) {
NSString *label = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(multi, i);
NSString *phone =(__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(multi, i);
NSLog(@"%@---%@", label, phone);
}
}
//选中联系人的某个属性再退出,要使用该方法,不能与上面的方法并存
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {
NSLog(@"%s",__func__);
}
@end
- 获取通讯录-AddressBook
实现步骤
- 请求授权
- 判断授权状态, 如果已授权, 则继续; 未授权, 则提示用户, 并返回;
- 创建通讯录对象
- 从通信录对象中, 获取所有的联系人
- 遍历所有的联系人
- 释放不再使用的对象
info.plist添加权限:Privacy - Contacts Usage Description
由于AddressBook也已经是过期的,swift3.0不再支持,所以只能用OC描述上述步骤
#import "ViewController.h"
#import <AddressBook/AddressBook.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self getAuthor];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
/*
kABAuthorizationStatusNotDetermined = 0,
kABAuthorizationStatusRestricted,
kABAuthorizationStatusDenied,
kABAuthorizationStatusAuthorized
*/
// 0. 判断当前的授权状态
if (ABAddressBookGetAuthorizationStatus() != kABAuthorizationStatusAuthorized) return;
// 1. 创建通讯录对象
ABAddressBookRef bookRef = ABAddressBookCreate();
// 2. 获取通讯录中所有的联系人
CFArrayRef arrayRef = ABAddressBookCopyArrayOfAllPeople(bookRef);
// 3. 遍历所有联系人
CFIndex count = CFArrayGetCount(arrayRef);
for (int i = 0; i < count; i++) {
ABRecordRef record = CFArrayGetValueAtIndex(arrayRef, i);
// 获取姓名
NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonFirstNameProperty);
NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonLastNameProperty);
NSLog(@"%@---%@", firstName, lastName);
// 获取电话号码
ABMultiValueRef multiValue = ABRecordCopyValue(record, kABPersonPhoneProperty);
CFIndex count = ABMultiValueGetCount(multiValue);
for (int i = 0; i < count; i ++) {
NSString *label = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(multiValue, i);
NSString *phone = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(multiValue, i);
NSLog(@"%@---%@", label, phone);
}
CFRelease(multiValue);
}
// 释放对象
CFRelease(bookRef);
CFRelease(arrayRef);
}
- (void)getAuthor
{
// 判断当前的授权状态是否是用户还未选择的状态
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRef bookRef = ABAddressBookCreate();
ABAddressBookRequestAccessWithCompletion(bookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
NSLog(@"授权成功!");
}
else
{
NSLog(@"授权失败!");
}
});
}
}
@end
ContactsUI.framework的使用
使用步骤
- 导入框架ContactsUI
- 创建选择联系人界面 CNContactPickerViewController
- 设置代理
- 弹出选择联系人界面的控制器
- 获取联系人
- 实现对应的代理方法
- 如果实现了选择联系人的代理方法,则无法进入详情界面
- 获取联系人的姓名
- 获取联系人的电话号码
import UIKit
import ContactsUI
class ViewController: UIViewController {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let vc = CNContactPickerViewController()
vc.delegate = self
present(vc, animated: true, completion: nil)
}
}
extension ViewController: CNContactPickerDelegate {
//1.退出联系人界面调用
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
print("通讯录界面退出")
}
//以下2,3,4,5方法不能同时使用
//2.当选中某个联系人调用
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
print("选中了联系人:" + contact.givenName + " " + contact.middleName + " " + contact.familyName)
for phoneNumber in contact.phoneNumbers {
print("\(phoneNumber.label!) : \(phoneNumber.value.stringValue)")
}
}
//3.选择多个联系人调用
func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
for contact in contacts {
print("选中了联系人:" + contact.givenName + " " + contact.middleName + " " + contact.familyName)
for phoneNumber in contact.phoneNumbers {
print("\(phoneNumber.label!) : \(phoneNumber.value.stringValue)")
}
}
}
//4.当选中某个联系人的某个属性调用 不能和2,3共同存在
func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
print("选中了联系人\(contactProperty.contact.familyName)的某个属性:\(contactProperty.key),其信息为:\(contactProperty.value)")
}
//5.当选中某个联系人的多个属性调用
func contactPicker(_ picker: CNContactPickerViewController, didSelectContactProperties contactProperties: [CNContactProperty]) {
for contactProperty in contactProperties {
print("选中了联系人\(contactProperty.contact.familyName)的某个属性:\(contactProperty.key),其信息为:\(contactProperty.value)")
}
}
}
iOS9.0之后的做法
Contacts.framework的使用
- 请求授权
- 获取授权状态
- 判断是否是未决定状态
- 请求授权
- 获取联系人
- 获取授权状态
- 判断是否是已经授权状态
- 创建联系人仓库
- 创建联系人的请求对象
- 获取用户的姓名
- 获取电话号码
info.plist加入Privacy - Contacts Usage Description权限
import UIKit
import Contacts
class ViewController: UIViewController {
//请求联系人仓库
//let store = CNContactStore()
lazy var store:CNContactStore? = {
if #available(iOS 9.0, *)
{
return CNContactStore()
} else {
return nil
}
}()
override func viewDidLoad() {
super.viewDidLoad()
let status = CNContactStore.authorizationStatus(for: .contacts)
if status == .notDetermined {
//请求授权
store?.requestAccess(for: .contacts, completionHandler: { (granted:Bool, e:Error?) in
if granted {
print("授权成功")
} else {
print("授权失败")
}
})
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//创建请求对象
let request = CNContactFetchRequest(keysToFetch: [CNContactFamilyNameKey as CNKeyDescriptor,CNContactPhoneNumbersKey as CNKeyDescriptor])
//遍历所有联系人信息
do{
try store?.enumerateContacts(with: request) { (contact:CNContact, stop:UnsafeMutablePointer<ObjCBool>) in
print(contact.familyName)
for number in contact.phoneNumbers {
print(number.label! + ":" + number.value.stringValue)
}
//*stop = YES(OC)
stop.initialize(to: true)
}
} catch {
print(error)
}
}
}