Get only new/modified phone contacts from iPhone

1.8k Views Asked by At

I want to import all phone contacts into app first time only and save on server.

Second time wants to imports only new, modified and deleted contacts into an app and sync with contacts saved on the server which should be done according to created/modified date of contacts.

From iOS 9, Apple won't allow to get create/modified date using Contacts Framework

How can I achieve with better approach?

3

There are 3 best solutions below

0
Neel Sonaje On BEST ANSWER

You can save contacts identifier and import date in local storage like SQLite. And when you receive contacts update notification, you can send saved date of respective updated contact and also update date in SQLite with received notification timestamp(date).

1
nerowolfe On

You should add observer for change contact list notification like this:

    NotificationCenter.default.addObserver(self,selector: #selector(self.addressBookDidChange(_:)), name: NSNotification.Name.CNContactStoreDidChange,object: nil)

And then

@objc func addressBookDidChange(_ notification: Notification){
    print(notification.object as Any, notification.userInfo as Any)
    //remove observer so far to prevent double method calling when making operations with contacts
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.CNContactStoreDidChange, object: nil)

    //processing


    //at some point return observer
    NotificationCenter.default.addObserver(self,selector: #selector(ContactsListVC.addressBookDidChange(_:)), name: NSNotification.Name.CNContactStoreDidChange,object: nil)



}
3
grebulon On

There's an undocumented API in CNContactStore - enumeratorForChangeHistoryFetchRequest:error:

I tried to test this method using the following code:

-(void)testChangeHistoryRequest {
    CNContactStore *store = [[CNContactStore alloc] init];
    [self requestContactsPermissions:store completion:^(BOOL granted) {
        if (!granted)
            return;
        NSData *storeToken = [store currentHistoryToken];
        NSLog(@"testChangeHistoryRequest: store token st start - %@", storeToken);
        NSError *error;
        CNChangeHistoryFetchRequest *req = [[CNChangeHistoryFetchRequest alloc] init];
        [req setAdditionalContactKeyDescriptors:@[CNContactGivenNameKey, CNContactFamilyNameKey]];
        [req setMutableObjects:YES];
        [req setShouldUnifyResults:YES];
        [req setStartingToken:storeToken];
        CNFetchResult<NSEnumerator<CNChangeHistoryEvent*>*>* res = [store enumeratorForChangeHistoryFetchRequest:req error:&error];
        if (res && res.value) {
            NSData *token = [res currentHistoryToken];
            NSLog(@"token - %@", token);
            for (CNChangeHistoryEvent *e in res.value)
                NSLog(@"%@ - %@", [e class], e);
            NSLog(@"token at end - %@", token);
        }
    }];
}

What I got is that store.currentHistoryToken never changes - it starts and ends with nil value. Also during the iteration, res.currentHistoryToken is always nil.

I also tried to initialize [req setStartingToken:storeToken]; with arbitrary data, but this changed nothing (and didn't even fail).

My guess is that this enumeration is not fully implemented.