Custom CloudKit sharing workflow

CloudKit has a strong emphasis on users privacy and security. Since one of the main concern for my last work - Lookii - was about users privacy, it was a good chance to investigate in deep about the real potential of the framework.

As of iOS10, CloudKit comes with a built-in feature related to sharing private data among participants on a container, namely CKShare. Unfortunately, there are very few articles about this topic on the internet and Apple documentation does not go in deep with advanced topics. All the relevant articles that I cited in the footnotes cover the basic flow of CloudKit sharing with some interesting variants that, however, didn’t fit exactly my case. I will not cover the basics, for that I will remand to the footnotes. Instead, I will focus on a specific and more advanced workflow that would be useful for someone else.

Suppose that you have an application that shares users information. Some of those need to be private and shared only among friends, while others should be publicly accessible from every participants in the container.

Let’s suppose that our CKRecord type is MyUser containing the following public information:

firstName: String
lastName: String
thumbnail: Data
privateShareUrl: String

some others data will not be flagged as public due to privacy concerns. For these we will use another CKRecord that we will call PrivateInfo, containing the following:

phoneNumber: String
email: String

This time, the record will not be part of public database. Instead, it will be saved on the private one — accessible exclusively from the owner of the record— and marked as part of a RecordZone that will be shared with selected participants.

A general scheme for the described use case could be something as follow:

As stated above, one of the main concern in using CloudKit sharing default workflow was related to the very basic UI customization options. Specifically, the basic workflow uses a very rigid schema:

Who share should be in charge of:

  1. Create the CKShare
  2. Pass it to a specific UICloudSharingController
  3. Create a URL to share using third party apps

Users that want to be added need to:

  1. Click on the link for accepting the shared url
  2. Implement some delegates on the UIApplication

Even if its straightforwardness makes it super easy to integrate, this approach lacks some advanced features. For example, I wouldn’t bother users with complicated flows that interrupt the natural experience of the app. Instead, I would like to run the workflow much as in the background, freeing source and destination from useless dialogs and app context switching.

It would be great, if I could select receivers of my private information by simple tapping the users icon in my app.

The first thing that we need to do is enabling userDiscoverability among app users, otherwise the rest of the process will not work due to privacy constraints.

Thanks god, Apple designed a very easy approach for this task and it requires only a simple access to user permission that you can manage to add in the early stage of your app:

Once the user granted his permission we are ready to go. Let’s create a very basic user CKRecord (the one that will be public):

Next, as part of the initial process, we need to create a specific zone that we will use to expose a view of our private records to selected users (our favorite friends):

Finally, we will create a private record containing all our valuable information:

Note that the record is tied to the CKRecordZone created early.

As you could point out, we still haven’t written the privateShareUrl field that is part of the public record; this is the crucial part of the whole approach described in this article. The standard behaviour, in fact, is based on the UICloudSharingController that will prompt the user with a dialog containing what and how to share the information. The result of the dialog is an URL that we need to use with third party apps such as Message, Email or whatever in order to communicate our intention to share something.

To make things even worst, on the other side, the receiver needs to click the link that, in turn, will open our app calling a corresponding UIApplocation delegate method. The latter, at the end, will give us a CKShareMetadata instance that we can use to fetch shared information.

Since our application already contains users, I would like to bypass this workflow by using the privateShareUrl field as an entry point for everyone that needs to fetch private information from a specific user.

Apple states that the share url for CKShare is stable and will not change unless you change the root record associated with it.

My plan is to simulate the basic sharing workflow by using the privateShareUrl field that we have on the public database for each user. This field will contain the original CKShare url. This way, every user that would like to fetch private information from a specific participant will access the url and check if he/she have access permission to the private fields exposed.

On the other hand, users that would like to share their private info with friends can simply add them to the share url, without bothering the receivers with third party apps and messages. Sounds great!

The first thing that we have to do is to create a default none access to our private information. This way, in the initial state no one can access our private data. Only when we add someone to the share, he would be able to access data. Apple, states that the default CKShare public permission is already configured for none access.

Now, every time an user would like to see private info shared by someone else will check the deisgnated privateShareUrl for the pertinent user:

Simple and effective. I have assembled a toy application with a complete use-case, available on GitHub at:

 advocate •📱architect