Search code examples
cloudkitcloudkit-sharing

How to Be Notified if the Owner Removes Me from a CKShare on CloudKit


Let's say the owner of a record shares it with me. I get sent a share link and I open it and accept the share like this:

let operation = CKAcceptSharesOperation(shareMetadatas: [metadata])
operation.acceptSharesCompletionBlock = { error in
  if let error = error{
    print("accept share error: \(error)")
  }else{
    //Share accepted...
  }
}
CloudKit.container.add(operation)

I am also previously subscribed to the Shared database already like so:

let subscriptionSharedDatabase = CKDatabaseSubscription(subscriptionID: "subscriptionSharedDatabase")
let sharedInfo = CKSubscription.NotificationInfo()
sharedInfo.shouldSendContentAvailable = true
sharedInfo.alertBody = "" //This needs to be set or pushes don't get sent
subscriptionSharedDatabase.notificationInfo = sharedInfo

let subShared = CKModifySubscriptionsOperation(subscriptionsToSave: [subscriptionSharedDatabase], subscriptionIDsToDelete: nil)
CloudKit.sharedDB.add(subShared)

But now let's say the owner of the CKShare removes me as a participant on that record and saves the updated participants list to CloudKit.

As far as I can tell, the only notification I get is another shared database subscription (subscriptionSharedDatabase) change, but no records are changed or deleted (I looked and there are no changed records when I fetch them).

As far as I know, the only way to be notified of changes to the participants on a CKShare is to subscribe to notifications on the cloudkit.share record type, but that isn't available to me in the shared database, right?

How can I be notified when I am removed from a CKShare?


Solution

  • Interesting how this has no answers. I just implemented some CKShare-related code and it seems to work fairly predictably. Here is the basic approach.

    1) at the start of my app, I do CKFetchRecordZonesOperation.fetchAllRecordZonesOperation() on the shared database, to get all the current record zones that are shared with me.

    2) I set up CKDatabaseSubscription on the shared database as you suggest.

    3) Upon receiving this notification on the shared database, I do a batch CKFetchRecordZoneChangesOperation across all the shared record zones. (You can pass it multiple record zones, together with a server change token for each zone, to do a bulk updates query.)

    4) If any shares were unshared but the record zones themselves are still valid, I observe that the recordWithIDWasDeletedBlock is run twice, once with the unshared CKRecord and once with the related CKShare.

    5) (I didn’t yet fully figure out this part) if the share was the last one for a given user, the whole shared record zone from that user gets removed from my shared database. I didn’t yet fully figure out how to best handle this part. I could query for fresh record zones every time I get a CKDatabaseNotification, but that seems wasteful. I see that I can run CKFetchDatabaseChanges operation that informs me of changed zones, but I have yet to figure out when is the best time to run it.