01.通讯录简介
通讯录应用场景
- 最常见的是一些即时通讯APP, 关联联系人;
通讯录获取方案
- AddressBookUI.framework 框架
提供了联系人列表界面、联系人详情界面、添加联系人界面等
一般用于选择联系人
- AddressBook.framework 框架
纯C语言的API,仅仅是获得联系人数据
没有提供UI界面展示,需要自己搭建联系人展示界面
里面的数据类型大部分基于Core Foundation框架,使用起来极其蛋疼
从iOS6开始,需要得到用户的授权才能访问通讯录,因此在使用之前,需要检查用户是否已经授权
- 第三方框架 RHAddressBook
对AddressBook.framework框架的封装
- iOS9.0最新通讯录获取框架
4.1 ContactsUI.framework == 方案1的替代品
特点: 面向对象, 使用简单. 有界面.
4.2 Contacts.framework == 方案2的替代品
特点: 面向对象, 使用简单. 无界面.
02 获取通讯录-AddressBookUI
- 实现代码
//1. 创建选择联系人的控制器
let adressVC = ABPeoplePickerNavigationController()
//2. 设置代理用来接受用户选择的联系人信息
adressVC.peoplePickerDelegate = self
//3. 弹出联系人控制器
present(adressVC, animated: true, completion: nil)
//4. 实现代理
//5. 在对应的代理方法中获取联系人信息
//取消选中联系人
func peoplePickerNavigationControllerDidCancel(_ peoplePicker: ABPeoplePickerNavigationController)
{
print("取消选中联系人")
}
// 选择某一个联系人时调用
func peoplePickerNavigationController(_ peoplePicker: ABPeoplePickerNavigationController, didSelectPerson person: ABRecord)
{
//ABRecord使用ABRecordCopyValue可以从一条Person记录中获取到对应的记录,
//但是后续处理则需要根据记录的具体类型加以区分
// 联系人里面的额记录, 分两个类型
// 简单属性, 姓名 ABRecordRef 可以直接使用
// 复杂属性, 联系人方式 家里电话, 办公电话 "标签" + "值" ABMultiValueRef
// Unmanaged<AnyObject>!
// swift , 使用CoreFoundation框架里面的类型, 分为两种
// 内存托管对象: 不需要我们程序员,手动去管理 CFString
// 内存非托管对象: 需要我们程序员, 手动管理内存
// takeRetainedValue: 如果方法名称里面有create, copy,
// takeUnretainedValue: 如果方法名称里面有get
//简单属性,
let firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeRetainedValue() as! String
let lastName = ABRecordCopyValue(person, kABPersonLastNameProperty).takeRetainedValue() as! String
print(lastName, firstName)
//复杂属性 取出联系人号码
let multiValue = ABRecordCopyValue(person, kABPersonPhoneProperty).takeRetainedValue() as ABMultiValue
//取出号码个数
let count = ABMultiValueGetCount(multiValue)
for i in 0..<count
{
// 每一个电话号码(标签+值) Unmanaged<CFString>!
// Unmanaged
let label = ABMultiValueCopyLabelAtIndex(multiValue, i).takeRetainedValue()
let value = ABMultiValueCopyValueAtIndex(multiValue, i).takeRetainedValue() as! String
print(label,value)
}
}
// 选择某一个联系人某一个属性时调用
// 如果上面一个选中某个联系人的方法, 实现了, 那么这个方法就不会再自行(因为界面压根都不会跳转到详情界面)
// 除非, 你把上面的方法,注释
func peoplePickerNavigationController(_ peoplePicker: ABPeoplePickerNavigationController, didSelectPerson person: ABRecord, property: ABPropertyID, identifier: ABMultiValueIdentifier)
{
print("选中某个联系人的某个属性")
}
AddressBook
- 实现代码
// 判断当前的授权状态, 如果没有授权, 则请求授权
// 在开发当中, 一般把授权, 放到代理里面
let status = ABAddressBookGetAuthorizationStatus()
if status == .notDetermined //用户拒绝
{// 请求访问通讯录的权限
// 参数1: 通讯录对象
// 参数2: 回调block
let ab = ABAddressBookCreate().takeRetainedValue()
ABAddressBookRequestAccessWithCompletion(ab)
{ (granted, error) in
if granted
{
print("授权成功")
}else
{
print("授权失败")
}
}
}
//判断状态
let status = ABAddressBookGetAuthorizationStatus()
if status != .authorized
{
print("当前没有访问权限")
}
//获取所有的联系人
//1. 创建通讯录对象
let ad = ABAddressBookCreate().takeRetainedValue()
//取出所有的联系人
let array : CFArray = ABAddressBookCopyArrayOfAllPeople(ad).takeRetainedValue()
// 2. 遍历里面所有的额对象记录
let count = CFArrayGetCount(array)
for i in 0..<count
{
// UnsafePointer<Void> == void * : 指向任意对象的zhizhen
// 需要把它转换成为, 一个特定的对象, 才可以使用
// swift 提供一个函数, 专门用于这种指针的转换
// unsafeBitCast, 但是, 使用这个函数, 一定要注意, 这个函数, 非常不安全, 必须明确的知道, 我们真正的结果是什么, 否则, 转换会失败
// 数组里面每一个对象, 都是一个联系人记录 ABRecord
let recordPoint = CFArrayGetValueAtIndex(array, i)
let record = unsafeBitCast(recordPoint, to: ABRecord.self)
//简单属性
let lastName = ABRecordCopyValue(record, kABPersonLastNameProperty).takeRetainedValue()
let firstName = ABRecordCopyValue(record, kABPersonFirstNameProperty).takeRetainedValue()
print(lastName,firstName)
//复杂属性
//电话号码
let multierValue = ABRecordCopyValue(record, kABPersonPhoneProperty).takeRetainedValue()
let count = ABMultiValueGetCount(multierValue)
//遍历电话号码
for j in 0..<count
{
let label = ABMultiValueCopyLabelAtIndex(multierValue, j).takeRetainedValue()
let number = ABMultiValueCopyValueAtIndex(multierValue, j).takeRetainedValue()
var phoneNnum = ""
if number != nil
{
phoneNnum = number as! String
}
print(label, phoneNnum)
}
}
}
IOS 9.0之后可以使用心得框架 ContactsUI.framework替代第一种方案
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
//1.创建一个控制器
let contackVC = CNContactPickerViewController()
//1.1设置代理
contackVC.delegate = self
//2.弹出控制器
present(contackVC, animated: true, completion: nil)
}
}
extension ViewController : CNContactPickerDelegate
{
//实现代理方法
func contactPickerDidCancel(_ picker: CNContactPickerViewController)
{
print("取消选择联系人")
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact)
{
//选择y一个联系人时候调用
print("选择联系人")
let familyName = contact.familyName
let givenName = contact.givenName
print(familyName,givenName)
let phoneNumbers = contact.phoneNumbers
for phoneNumber in phoneNumbers
{
let label = phoneNumber.label
let value = phoneNumber.value
print(label, value)
}
}
// func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact])
// {//选择多个联系人时调用
// print("选择多个联系人")
//
// }
// 选择某一个联系人的某一个属性时调用
// 如果想要选择某一个属性, 需要把上面的方法注释
// func contactPicker(picker: CNContactPickerViewController, didSelectContactProperty contactProperty: CNContactProperty) {
// print("选择某一个联系人的某一个属性时调用")
// }
}
Contacts.framework使用,替代第二种方案
- 代码实现
import UIKit
import Contacts
class ViewController: UIViewController
{
//1. 创建联系人仓库
@available(iOS 9.0, *)
var store: CNContactStore {
return CNContactStore()
}
override func viewDidLoad()
{
super.viewDidLoad()
// 判断授权状态, 请求授权
if #available(iOS 9.0, *)
{
let status = CNContactStore.authorizationStatus(for: .contacts)
if status == .notDetermined
{
// 请求授权
// 1. 创建联系人仓库
// let store = CNContactStore()
// 2. 请求授权
let tempStore = store
tempStore.requestAccess(for: .contacts)
{ (granted, error) in
if granted
{
print("授权成功")
}else
{
print("授权失败")
}
}
}
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
if #available(iOS 9.0, *)
{
// 0. 判断是否授权成功
let status = CNContactStore.authorizationStatus(for: .contacts)
if status != .authorized
{
print("没有权限")
}
else
{
print("获得权限")
}
// 取出所有联系人
// 1. 创建请求对象
// 过滤一些字段(凡是写到这个数组里面的, 都代表, 你要获取的字段)
let quest = CNContactFetchRequest(keysToFetch: [CNContactFamilyNameKey as NSString, CNContactPhoneNumbersKey as NSString])
//开始便利
do
{
let tempStore = store
try tempStore.enumerateContacts(with: quest, usingBlock:
{ (contact, stop) in
let fanmilyName = contact.familyName
print(fanmilyName)
let phoneNumbers = contact.phoneNumbers
for num in phoneNumbers
{
let label = num.label
let numberStr = num.value
print(label , numberStr.stringValue)
}
//stop.pointee = true
})
} catch
{
print(error)
}
}
}
}
网友评论