57

我知道 ios swift 有一个联系人框架,我可以在其中获取联系人,但我找不到任何方法来一起获取所有联系人,我可以从该数组中访问每个联系人。所有获取联系人的方法似乎都需要某种条件。有什么方法可以将所有联系人放在一起吗?

谢谢

4

8 回答 8

43

斯威夫特 4 和 5。我已经创建了 PhoneContacts 类。请将 NSContactsUsageDescription 键添加到您的 info.plist 文件中

 import Foundation
 import ContactsUI

class PhoneContacts {

    class func getContacts(filter: ContactsFilter = .none) -> [CNContact] { //  ContactsFilter is Enum find it below

        let contactStore = CNContactStore()
        let keysToFetch = [
            CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
            CNContactPhoneNumbersKey,
            CNContactEmailAddressesKey,
            CNContactThumbnailImageDataKey] as [Any]

        var allContainers: [CNContainer] = []
        do {
            allContainers = try contactStore.containers(matching: nil)
        } catch {
            print("Error fetching containers")
        }

        var results: [CNContact] = []

        for container in allContainers {
            let fetchPredicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier)

            do {
                let containerResults = try contactStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keysToFetch as! [CNKeyDescriptor])
                results.append(contentsOf: containerResults)
            } catch {
                print("Error fetching containers")
            }
        }
        return results
    }
}

在另一个类中调用上述方法

import ContactsUI
func phoneNumberWithContryCode() -> [String] {

    let contacts = PhoneContacts.getContacts() // here calling the getContacts methods
    var arrPhoneNumbers = [String]()
    for contact in contacts {
        for ContctNumVar: CNLabeledValue in contact.phoneNumbers {
            if let fulMobNumVar  = ContctNumVar.value as? CNPhoneNumber {
                //let countryCode = fulMobNumVar.value(forKey: "countryCode") get country code
                   if let MccNamVar = fulMobNumVar.value(forKey: "digits") as? String {
                        arrPhoneNumbers.append(MccNamVar)
                }
            }
        }
    }
    return arrPhoneNumbers // here array has all contact numbers.
}

现在,获取联系人的电子邮件和电话

    enum ContactsFilter {
        case none
        case mail
        case message
    }

    var phoneContacts = [PhoneContact]() // array of PhoneContact(It is model find it below) 
    var filter: ContactsFilter = .none

    self.loadContacts(filter: filter) // Calling loadContacts methods

       fileprivate func loadContacts(filter: ContactsFilter) {
            phoneContacts.removeAll()
            var allContacts = [PhoneContact]()
            for contact in PhoneContacts.getContacts(filter: filter) {
                allContacts.append(PhoneContact(contact: contact))
            }

            var filterdArray = [PhoneContact]()
            if self.filter == .mail {
                filterdArray = allContacts.filter({ $0.email.count > 0 }) // getting all email 
            } else if self.filter == .message {
                filterdArray = allContacts.filter({ $0.phoneNumber.count > 0 })
            } else {
                filterdArray = allContacts
            }
            phoneContacts.append(contentsOf: filterdArray)

  for contact in phoneContacts {
      print("Name -> \(contact.name)")
      print("Email -> \(contact.email)")
      print("Phone Number -> \(contact.phoneNumber)")
    }
    let arrayCode  = self.phoneNumberWithContryCode()
    for codes in arrayCode {
      print(codes)
    }
     DispatchQueue.main.async {
       self.tableView.reloadData() // update your tableView having phoneContacts array
              }
            }
        }

PhoneContact 模型类

import Foundation
import ContactsUI

class PhoneContact: NSObject {

    var name: String?
    var avatarData: Data?
    var phoneNumber: [String] = [String]()
    var email: [String] = [String]()
    var isSelected: Bool = false
    var isInvited = false

    init(contact: CNContact) {
        name        = contact.givenName + " " + contact.familyName
        avatarData  = contact.thumbnailImageData
        for phone in contact.phoneNumbers {
            phoneNumber.append(phone.value.stringValue)
        }
        for mail in contact.emailAddresses {
            email.append(mail.value as String)
        }
    }

    override init() {
        super.init()
    }
}
于 2017-12-19T12:36:43.847 回答
40

Contact Framework 问题的许多答案都建议对各种容器(帐户)进行迭代。但是,Apple 的文档将“统一联系人”描述为

代表同一个人的不同帐户中的联系人可能会自动链接在一起。链接的联系人在 OS X 和 iOS 应用程序中显示为统一联系人。统一联系人是合并到一个联系人中的一组链接联系人的内存中临时视图。

默认情况下,联系人框架返回统一联系人。每个获取的统一联系人 (CNContact) 对象都有其自己的唯一标识符,该标识符不同于链接联系人集中的任何单个联系人的标识符。应使用其标识符重新获取统一联系人。 资源

因此,在单个数组中获取(部分,基于键)联系人列表的最简单方法如下:

      var contacts = [CNContact]()
    let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)]
    let request = CNContactFetchRequest(keysToFetch: keys)
    
    let contactStore = CNContactStore()
    do {
        try contactStore.enumerateContacts(with: request) {
            (contact, stop) in
            // Array containing all unified contacts from everywhere
            contacts.append(contact)
        }
    }
    catch {
        print("unable to fetch contacts")
    }
于 2016-05-23T10:22:14.800 回答
28

Swift 4 的更新

let contactStore = CNContactStore()
var contacts = [CNContact]()
let keys = [
        CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
                CNContactPhoneNumbersKey,
                CNContactEmailAddressesKey
        ] as [Any]
let request = CNContactFetchRequest(keysToFetch: keys as! [CNKeyDescriptor])
do {
    try contactStore.enumerateContacts(with: request){
            (contact, stop) in
        // Array containing all unified contacts from everywhere
        contacts.append(contact)
        for phoneNumber in contact.phoneNumbers {
            if let number = phoneNumber.value as? CNPhoneNumber, let label = phoneNumber.label {
                let localizedLabel = CNLabeledValue<CNPhoneNumber>.localizedString(forLabel: label)
                print("\(contact.givenName) \(contact.familyName) tel:\(localizedLabel) -- \(number.stringValue), email: \(contact.emailAddresses)")
            }
        }
    }
    print(contacts)
} catch {
    print("unable to fetch contacts")
}
于 2018-03-06T11:12:55.437 回答
7
    // You may add more "keys" to fetch referred to official documentation
    let keysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName)]

    // The container means 
    // that the source the contacts from, such as Exchange and iCloud
    var allContainers: [CNContainer] = []
    do {
        allContainers = try store.containersMatchingPredicate(nil)
    } catch {
        print("Error fetching containers")
    }

    var contacts: [CNContact] = []

    // Loop the containers
    for container in allContainers {
        let fetchPredicate = CNContact.predicateForContactsInContainerWithIdentifier(container.identifier)

        do {
            let containerResults = try store.unifiedContactsMatchingPredicate(fetchPredicate, keysToFetch: keysToFetch)
            // Put them into "contacts"
            contacts.appendContentsOf(containerResults)
        } catch {
            print("Error fetching results for container")
        }
    }
于 2016-05-09T05:31:08.067 回答
6

用于拉入所有联系人的 Swift 4.0 实现。

let contactStore = CNContactStore()
var contacts = [CNContact]()
let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)]
let request = CNContactFetchRequest(keysToFetch: keys)

do {
    try contactStore.enumerateContacts(with: request) { (contact, stop) in
        contacts.append(contact)
    }
} catch {
    print(error.localizedDescription)
}

这将创建一个本地属性来存储联系人,然后通过针对 的枚举来填充这些联系人contactStore

于 2018-02-28T03:59:27.983 回答
3

请查看我的答案,它基于上面的答案并进行了某些改进,只需执行以下操作

在你的 pod 文件中

source 'https://github.com/CocoaPods/Specs.git'
pod 'PhoneNumberKit', '~> 2.6'

然后运行 ​​pod install

然后在您的 ViewController 文件中

import Contacts
import PhoneNumberKit
import UIKit

override func viewDidLoad() {
    super.viewDidLoad()

    let contactStore = CNContactStore()
    var contacts = [CNContact]()
    let keys = [
        CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
        CNContactPhoneNumbersKey,
        CNContactEmailAddressesKey,
    ] as [Any]
    let request = CNContactFetchRequest(keysToFetch: keys as! [CNKeyDescriptor])
    do {
        try contactStore.enumerateContacts(with: request) {
            contact, _ in
            // Array containing all unified contacts from everywhere
            contacts.append(contact)
            for phoneNumber in contact.phoneNumbers {
                if let number = phoneNumber.value as? CNPhoneNumber, let label = phoneNumber.label {
                    let localizedLabel = CNLabeledValue<CNPhoneNumber>.localizedString(forLabel: label)

                    // Get The Name
                    let name = contact.givenName + " " + contact.familyName
                    print(name)

                    // Get The Mobile Number
                    var mobile = number.stringValue
                    mobile = mobile.replacingOccurrences(of: " ", with: "")

                    // Parse The Mobile Number
                    let phoneNumberKit = PhoneNumberKit()

                    do {
                        let phoneNumberCustomDefaultRegion = try phoneNumberKit.parse(mobile, withRegion: "IN", ignoreType: true)
                        let countryCode = String(phoneNumberCustomDefaultRegion.countryCode)
                        let mobile = String(phoneNumberCustomDefaultRegion.nationalNumber)
                        let finalMobile = "+" + countryCode + mobile
                        print(finalMobile)
                    } catch {
                        print("Generic parser error")
                    }

                    // Get The Email
                    var email: String
                    for mail in contact.emailAddresses {
                        email = mail.value as String
                        print(email)
                    }
                }
            }
        }

    } catch {
        print("unable to fetch contacts")
    }
}
于 2019-06-21T02:04:33.877 回答
2

请尝试以下功能,它可以帮助您(Swift 4)

import UIKit
import Contacts
import ContactsUI

override func viewDidLoad() {
    super.viewDidLoad()

    // `contacts` Contains all details of Phone Contacts
    let contacts = self.getContactFromCNContact() 
    for contact in contacts {

        print(contact.middleName)
        print(contact.familyName)
        print(contact.givenName)
    }
}

func getContactFromCNContact() -> [CNContact] {

    let contactStore = CNContactStore()
    let keysToFetch = [
        CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
        CNContactGivenNameKey,
        CNContactMiddleNameKey,
        CNContactFamilyNameKey,
        CNContactEmailAddressesKey,
        ] as [Any]

    //Get all the containers
    var allContainers: [CNContainer] = []
    do {
        allContainers = try contactStore.containers(matching: nil)
    } catch {
        print("Error fetching containers")
    }

    var results: [CNContact] = []

    // Iterate all containers and append their contacts to our results array
    for container in allContainers {

        let fetchPredicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier)

        do {
            let containerResults = try contactStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keysToFetch as! [CNKeyDescriptor])
            results.append(contentsOf: containerResults)

        } catch {
            print("Error fetching results for container")
        }
    }

    return results
}
于 2019-08-08T05:10:37.600 回答
1

复杂的解决方案:

var contacts = [CNContact]()

let keys: [Any] = [
    CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
    CNContactImageDataKey,
    CNContactEmailAddressesKey,
    CNContactPhoneNumbersKey,
    CNContactJobTitleKey,
    CNContactBirthdayKey,
    CNContactPostalAddressesKey
]

let request = CNContactFetchRequest(keysToFetch: keys as! [CNKeyDescriptor])
let contactStore = CNContactStore()

try? contactStore.enumerateContacts(with: request, usingBlock: { contact, _ in
    contacts.append(contact)
})

不要忘记 Info.plist:

NSContactsUsageDescription
于 2021-09-02T15:18:52.833 回答