CNContactStoreWrapper is a SPM library for interacting with CNContactStore.
To enumerate changes to the CNContactStore we must use the method enumeratorForChangeHistoryFetchRequest. This method is only exposed in Obj-C so we can wrap the store in an Obj-C class and expose the result to Swift.
You can add CNContactStoreWrapper to an Xcode project by adding it as a package dependency.
If you want to use CNContactStoreWrapper in a SwiftPM project, it's as simple as adding it to a dependencies clause in your Package.swift:
dependencies: [
.package(url: "https://github.com/MultiScott/CNContactStoreWrapper", from: "0.2.1")
]import CNContactStoreWrapper
...
let fetchRequest = CNChangeHistoryFetchRequest()
fetchRequest.startingToken = self.currentHistoryToken
fetchRequest.shouldUnifyResults = true
let wrapper = CNContactStoreWrapper(store: contactStore)
let result = wrapper.changeHistoryFetchResult(fetchRequest, error: nil)
guard let enumerator = result.value as? NSEnumerator else {
throw ContactError.failedToCreateNSEnumeratorForChangeHistory
}
enumerator
.compactMap {
$0 as? CNChangeHistoryEvent
}
.forEach { event in
switch event {
case let addContactEvent as CNChangeHistoryAddContactEvent:
print("Added Contact: \(addContactEvent.contact.identifier)")
// Handle adding to your local store
case let updateContactEvent as CNChangeHistoryUpdateContactEvent:
print("Updated Contact: \(updateContactEvent.contact.identifier)")
// Handle updating in your local store
case let deleteContactEvent as CNChangeHistoryDeleteContactEvent:
print("Deleted Contact with ID: \(deleteContactEvent.contactIdentifier)")
// Handle deletion in your local store
case let addGroupEvent as CNChangeHistoryAddGroupEvent:
print("Added Group: \(addGroupEvent.group.identifier)")
// Handle group addition if needed
case let updateGroupEvent as CNChangeHistoryUpdateGroupEvent:
print("Updated Group: \(updateGroupEvent.group.identifier)")
// Handle group updates if needed
case let deleteGroupEvent as CNChangeHistoryDeleteGroupEvent:
print("Deleted Group with ID: \(deleteGroupEvent.groupIdentifier)")
// Handle group deletion if needed
case let addMemberEvent as CNChangeHistoryAddMemberToGroupEvent:
print("Added member \(addMemberEvent.member.identifier) to group \(addMemberEvent.group.identifier)")
// Handle member addition
case let removeMemberEvent as CNChangeHistoryRemoveMemberFromGroupEvent:
print("Removed member \(removeMemberEvent.member.identifier) from group \(removeMemberEvent.group.identifier)")
// Handle member removal
default:
break
}
}This solution was inspired and informed by this StackOverFlow post answered by andercover.