Skip to content

Instantly share code, notes, and snippets.

@iAmrSalman
Last active May 26, 2021 21:25
Show Gist options
  • Save iAmrSalman/27a6205938fa1638e950457e7517ce91 to your computer and use it in GitHub Desktop.
Save iAmrSalman/27a6205938fa1638e950457e7517ce91 to your computer and use it in GitHub Desktop.
[ContactsManager] fetch all contacts from Phone Contacts using Contacts framework #swift4 #contacts
import Foundation
import ContactsUI
enum ContactsFilter {
case none
case mail
case message
}
struct PhoneContact {
var givenName: String
var middleName: String
var familyName: String
var number: String
var numberLabel: String
var fullName: String {
return "\(givenName)\(middleName.isEmpty ? "" : " \(middleName)")\(familyName.isEmpty ? "" : " \(familyName)")"
}
var numberFormatted: String {
do {
return try PhoneNumberManager.validate(number, with: .e164)
} catch {
return ""
}
}
var json: [String: String] {
return ["mobileNumber": numberFormatted, "contactName": fullName]
}
}
class ContactsManager {
//MARK: - Properties
static let manager = ContactsManager()
//MARK: - Helpers
private func getContacts(from contactStore: CNContactStore, filter: ContactsFilter = .none) -> [CNContact] {
var results: [CNContact] = []
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactPhoneNumbersKey] as [Any]
var allContainers: [CNContainer] = []
do {
allContainers = try contactStore.containers(matching: nil)
} catch {
return results
}
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 {
return results
}
}
return results
}
private func contactsAuthorization(for store: CNContactStore, completionHandler: @escaping ((_ isAuthorized: Bool) -> Void)) {
let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts)
switch authorizationStatus {
case .authorized:
completionHandler(true)
case .notDetermined:
store.requestAccess(for: CNEntityType.contacts, completionHandler: { (isAuthorized: Bool, error: Error?) in
completionHandler(isAuthorized)
})
case .denied:
completionHandler(false)
case .restricted:
completionHandler(false)
}
}
private func parse(_ contact: CNContact) -> PhoneContact? {
for phoneNumber in contact.phoneNumbers {
if let label = phoneNumber.label {
let number = phoneNumber.value
let localizedLabel = CNLabeledValue<CNPhoneNumber>.localizedString(forLabel: label)
return PhoneContact(givenName: contact.givenName, middleName: contact.middleName, familyName: contact.familyName, number: number.stringValue, numberLabel: localizedLabel)
}
}
return nil
}
//MARK: - Actions
func fetchAllContacts(completionHandler: @escaping (([PhoneContact], Error?) -> Void)) {
var phoneContacts = [PhoneContact]()
let contactStore = CNContactStore()
contactsAuthorization(for: contactStore) { isAuthorized in
if isAuthorized {
let contacts = self.getContacts(from: contactStore)
for contact in contacts {
if let phoneContact = self.parse(contact) {
if phoneContact.givenName != "SPAM" && phoneContact.numberFormatted != "" {
phoneContacts.append(phoneContact)
}
} else {
continue
}
}
completionHandler(phoneContacts, nil)
} else {
completionHandler(phoneContacts, MCError.NotAuthorized)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment