Swift:JKContactsKit 获取通讯录的联系人

JKSwiftExtension,测试用例在 JKContactsKitViewController 里面
目录:

  • 1、简介和CNKeyDescriptor的key介绍
  • 2、通讯录的基本使用
    • 获取授权状态
    • 查询出所有通讯录信息
    • 添加新联系人
    • 更新联系人
    • 删除联系人

一、简介和CNKeyDescriptor的key介绍

  • 1.1、在 iOS9.0 之前, 我们只能通过 AddressBook 框架来获取通讯录联系人信息。但 AddressBook framework 语法很奇怪,同时也十分难用。所以苹果从 iOS9.0 开始推出的全新的联系人框架 Contacts FrameWork 作为替代,同时将原来的 AddressBook 给废弃掉。

  • 1.2、Contacts FrameWork 同样包含两种访问通讯录的方式:

    • ContactsUI.framework 框架 : 通过系统提供的通讯录交互界面来访问(替代原先的 AddressBookUI.framework)
    • Contacts.framework 框架 : 没有界面,通过代码来获取所有联系人信息(替代原先的 AddressBook.framework)

    由于苹果安全策略更新,在使用 Xcode8 开发时,需要在 Info.plist 配置请求通讯录的相关描述字段(Privacy - Contacts Usage Description

  • 1.3、CNKeyDescriptor的key介绍

    //  标识符
    @available(iOS 9.0, *)
    public let CNContactIdentifierKey: String
    // 姓名前缀
    @available(iOS 9.0, *)
    public let CNContactNamePrefixKey: String
    // 姓名
    @available(iOS 9.0, *)
    public let CNContactGivenNameKey: String
    // 中间名
    @available(iOS 9.0, *)
    public let CNContactMiddleNameKey: String
    // 姓氏
    @available(iOS 9.0, *)
    public let CNContactFamilyNameKey: String
    // 之前的姓氏(ex:国外的女士)
    @available(iOS 9.0, *)
    public let CNContactPreviousFamilyNameKey: String
    // 姓名后缀
    @available(iOS 9.0, *)
    public let CNContactNameSuffixKey: String
    // 昵称
    @available(iOS 9.0, *)
    public let CNContactNicknameKey: String
    // 公司(组织)
    @available(iOS 9.0, *)
    public let CNContactOrganizationNameKey: String
    // 部门
    @available(iOS 9.0, *)
    public let CNContactDepartmentNameKey: String
    // 职位
    @available(iOS 9.0, *)
    public let CNContactJobTitleKey: String
    // 名字的拼音或音标
    @available(iOS 9.0, *)
    public let CNContactPhoneticGivenNameKey: String
    // 中间名的拼音或音标
    @available(iOS 9.0, *)
    public let CNContactPhoneticMiddleNameKey: String
    // 形式的拼音或音标
    @available(iOS 9.0, *)
    public let CNContactPhoneticFamilyNameKey: String
    // 公司(组织)的拼音或音标(iOS10 才开始存在的呢)
    @available(iOS 10.0, *)
    public let CNContactPhoneticOrganizationNameKey: String
    // 生日
    @available(iOS 9.0, *)
    public let CNContactBirthdayKey: String
    // 农历
    @available(iOS 9.0, *)
    public let CNContactNonGregorianBirthdayKey: String
    // 备注
    @available(iOS 9.0, *)
    public let CNContactNoteKey: String
    // 头像
    @available(iOS 9.0, *)
    public let CNContactImageDataKey: String
    // 头像的缩略图
    @available(iOS 9.0, *)
    public let CNContactThumbnailImageDataKey: String
    // 头像是否可用
    @available(iOS 9.0, *)
    public let CNContactImageDataAvailableKey: String
    // 类型
    @available(iOS 9.0, *)
    public let CNContactTypeKey: String
    // 电话号码
    @available(iOS 9.0, *)
    public let CNContactPhoneNumbersKey: String
    // 邮箱地址
    @available(iOS 9.0, *)
    public let CNContactEmailAddressesKey: String
    // 住址
    @available(iOS 9.0, *)
    public let CNContactPostalAddressesKey: String
    // 其他日期
    @available(iOS 9.0, *)
    public let CNContactDatesKey: String
    // url地址
    @available(iOS 9.0, *)
    public let CNContactUrlAddressesKey: String
    // 关联人
    @available(iOS 9.0, *)
    public let CNContactRelationsKey: String
    // 社交
    @available(iOS 9.0, *)
    public let CNContactSocialProfilesKey: String
    // 即时通信
    @available(iOS 9.0, *)
    public let CNContactInstantMessageAddressesKey: String
    

二、通讯录的基本使用

  • 2.1、获取授权状态

    // MARK: 1.1、获取授权状态
    /// 获取授权状态
    /// - Returns: 授权状态
    static func authorizationStatus() -> CNAuthorizationStatus {
        // 获取授权状态
        return CNContactStore.authorizationStatus(for: .contacts)
    }
    
  • 2.2、查询出所有通讯录信息

    // MARK: 1.2、获取通讯录的信息
    /// 获取通讯录的信息
    /// - Parameter keys: 获取Fetch,并且指定之后要获取联系人中的什么属性
    ///   - completion: 结果闭包
    static func selectContactsData(keys: [String] = [CNContactFamilyNameKey, CNContactGivenNameKey, CNContactOrganizationNameKey, CNContactPhoneNumbersKey, CNContactNicknameKey], completion: @escaping (([CNContact], Error?) -> Void)) {
         // 创建通讯录对象
         let store = CNContactStore()
         store.requestAccess(for: .contacts) {(granted, error) in
             if (granted) && (error == nil) {
                 // 创建请求对象 需要传入一个(keysToFetch: [CNKeyDescriptor]) 包含'CNKeyDescriptor'类型的数组
                 let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor])
                 do {
                     var contacts: [CNContact] = []
                     // 需要传入一个CNContactFetchRequest
                     try store.enumerateContacts(with: request, usingBlock: {(contact : CNContact, stop : UnsafeMutablePointer) -> Void in
                         contacts.append(contact)
                     })
                     completion(contacts, nil)
                 } catch {
                     completion([], nil)
                 }
             } else {
                 completion([], error)
             }
         }
    }
    
  • 2.3、添加新联系人

    // MARK: 1.3、添加新联系人
    /// 添加新联系人
    /// - Parameters:
    ///   - contact: 联系人的信息
    ///   - completion: 结果闭包
    static func addContactItem(contact: CNMutableContact, completion: @escaping ((Bool, Error?) -> Void)) {
         // 创建通讯录对象
         let store = CNContactStore()
         store.requestAccess(for: .contacts) {(granted, error) in
             if (granted) && (error == nil) {
                 // 添加联系人请求
                 let saveRequest = CNSaveRequest()
                 saveRequest.add(contact, toContainerWithIdentifier: nil)
                 do {
                     // 写入联系人
                     try store.execute(saveRequest)
                     completion(true, nil)
                 } catch {
                     completion(true, error)
                }
             } else {
                 completion(false, error)
             }
         }
    }
    
  • 2.4、更新联系人

    // MARK: 1.4、更新联系人
    /// 更新联系人
    /// - Parameters:
    ///   - identifier: 唯一标识符
    ///   - familyName: 姓氏
    ///   - givenName: 名字
    ///   - phoneNumbers: 手机号码数组
    ///   - keys: key
    ///   - completion: 结果闭包
    static func updateContactItem(identifier: String, familyName: String, givenName: String, phoneNumbers: [CNLabeledValue<CNPhoneNumber>], keys: [String] = [CNContactFamilyNameKey, CNContactGivenNameKey, CNContactOrganizationNameKey, CNContactPhoneNumbersKey, CNContactNicknameKey], completion: @escaping ((Bool, Error?) -> Void)) {
      // 创建通讯录对象
      let store = CNContactStore()
      store.requestAccess(for: .contacts) {(granted, error) in
          if (granted) && (error == nil) {
              guard let itemContact = try? store.unifiedContact(withIdentifier: identifier, keysToFetch: keys as [CNKeyDescriptor]) else {
                  return
              }
              let mutableContact = itemContact.mutableCopy() as! CNMutableContact
              mutableContact.familyName = familyName
              mutableContact.givenName = givenName
              mutableContact.phoneNumbers = phoneNumbers
              // 修改联系人请求
              let request = CNSaveRequest()
              request.update(mutableContact)
              do {
                  // 修改联系人
                  try store.execute(request)
                  completion(true, error)
              } catch {
                  completion(false, error)
              }
          } else {
              completion(false, error)
          }
      }
    }
    
  • 2.5、删除联系人

    // MARK: 1.5、删除联系人
    /// 删除联系人
    /// - Parameters:
    ///   - identifier: 唯一标识符
    ///   - keys: key
    ///   - completion: 结果闭包
    static func deleteContactItem(identifier: String, keys: [String] = [CNContactFamilyNameKey, CNContactGivenNameKey, CNContactOrganizationNameKey, CNContactPhoneNumbersKey, CNContactNicknameKey], completion: @escaping ((Bool, Error?) -> Void)) {
        // 创建通讯录对象
        let store = CNContactStore()
        store.requestAccess(for: .contacts) {(granted, error) in
            if (granted) && (error == nil) {
                guard let itemContact = try? store.unifiedContact(withIdentifier: identifier, keysToFetch: keys as [CNKeyDescriptor]) else {
                    return
                }
                let mutableContact = itemContact.mutableCopy() as! CNMutableContact
                // 删除联系人请求
                let request = CNSaveRequest()
                request.delete(mutableContact)
                do {
                    // 执行操作
                    try store.execute(request)
                    completion(true, error)
                } catch {
                    completion(false, error)
                }
            } else {
                completion(false, error)
            }
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349