Last active
May 26, 2021 21:25
-
-
Save iAmrSalman/27a6205938fa1638e950457e7517ce91 to your computer and use it in GitHub Desktop.
[ContactsManager] fetch all contacts from Phone Contacts using Contacts framework #swift4 #contacts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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