美文网首页
IOS 通讯录 访问和使用

IOS 通讯录 访问和使用

作者: 越天高 | 来源:发表于2020-06-02 17:22 被阅读0次

    01.通讯录简介

    通讯录应用场景

    1. 最常见的是一些即时通讯APP, 关联联系人;

    通讯录获取方案

    1. AddressBookUI.framework 框架

    提供了联系人列表界面、联系人详情界面、添加联系人界面等
    一般用于选择联系人

    1. AddressBook.framework 框架

    纯C语言的API,仅仅是获得联系人数据
    没有提供UI界面展示,需要自己搭建联系人展示界面
    里面的数据类型大部分基于Core Foundation框架,使用起来极其蛋疼
    从iOS6开始,需要得到用户的授权才能访问通讯录,因此在使用之前,需要检查用户是否已经授权

    1. 第三方框架 RHAddressBook

    对AddressBook.framework框架的封装

    1. 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)
                }
                
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:IOS 通讯录 访问和使用

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