Sharing Data with Siri and Realm
By: Tribalscale Inc.
Tags: Realm, Apple, Siri, Tutorial, Data Sharing

by Justin Lycklama, Agile Software Engineer

Using Siri to get information from the user into your application is not straightforward. The code you write for SiriKit does not live in the same target as your main application, and by default, you cannot share data between the two.

image of Amazon Echo

Let’s dive into the connection between our app and Siri by first creating an Extension for Siri. This is a good time to mention that as of right now, developing an app with the Siri capability requires membership in the Apple Developer Program. You can check here for a list of what capabilities require ADP.

grey and purple graphic showing flow for setting up an extension for Siri

Step 1. Create an app extension

When a user asks Siri to perform an action, Siri will handle the language processing and transform the user’s request into an Intent. Let’s create a new Target to handle certain Intents by selecting File -> New -> Target and searching for Intent. Leave the starting point as Messaging even if you are not planning to use a messaging Intent to see how it is set up by default.

For now, we are going to be creating an Intents Extension to handle saving data when the user initiates our Intent. If you want to customize Siri’s UI, you should look into the Intents UI Extension as well.

Step 2. Add the Siri Capability

In addition to adding the extension, you will also have to add the Capability in the Apple Developer Portal to your apps identifier. I’ll assume you are familiar with the basics of certificates, identifiers, and profiles.

Step 3. Specify which Intents your app can handle

I’m going to add a custom Intent, but you can skip this step if you choose. There is a default collection of System Intents that should be used if they fit your use case. For example, if you want to send a message you can use the Intent INSendMessageIntent. For my purposes, I’m going to create a custom Intent to store some data when requested.

To create a custom Intent, add a new file and search for SiriKit Intent Definition File. From this file you can configure custom Intents. For this project, I’ve simply called my custom Intent NewItem.

Once you have decided on your Intent, open your Project editor in Xcode and navigate to the general tab of your new extension Target. Here you can specify which Intents you want SiriKit to route to your extension. I’ve removed the three default cases and added my new Intent ‘NewItemIntent’.

Notice the suffix added to ‘NewItem’ as ‘NewItemIntent’. When you define a custom Intent in an Intent Definition File, a class and a protocol are automatically generated for you with the suffix ‘Intent’.

Next, let’s use the Intent that has been routed to our extension.

Step 4. Intent Handling

When we created our Intent Extension, Xcode automatically created an IntentHandler class for us. The class is a bit overwhelming at first so let’s break it down into parts:

The IntentHandler that conforms to INExtension is that object that will get Intents from Siri routed to this extension. What it needs to return is an object that implements the Handling protocol specific to the type of Intent we have received.

Notice the three other protocols the IntentHandler conforms to are directly related to the three default Supported Intents the target has when using the starting point Messaging: INSendMessageIntent, INSearchForMessagesIntent, and INSetMessageAttributeIntent.

The rest of the generated code can now be simplified as handling each of these cases. To handle any specific Intent, we have to implement a method called ‘handle’ that takes in our Intent and returns the response specific to that Intent.

Now that we understand the flow, why don’t we create our own Intent handler. Remember how Xcode automatically generated us a file with the NewItemIntent class? In that same file it also generates a protocol which handles our Intent.

This handler receives our Intent type and uses our response type in the completion block. Now, we simply have to create a handler adhering to this protocol if we receive our custom Intent type.

Part 5: Sharing Data: Creating App Groups

Before we begin sharing data between our main app and our extension, let’s begin by setting up a database. I’m going to be using the Realm database, as I find it to be easy to use, and it integrates nicely with RxSwift. As SwiftUI and Combine mature, it might become simpler to use a native approach. Time being, this is my preferred solution.

What if we try creating an instance of Realm in our Intent handler? We can save data to our instance, but since the handler is in an extension, none of the data will be accessible from outside. This is where App Groups come into play!

The extension’s code is contained within our app’s bundle, but where our extension’s data is stored is distinctly different from where our application data is. To solve this, we can add both to a single App Group. To create the App Group, look in the Identifiers section of the developers portal and change the filter type from App IDs to App Groups.

Image of list of App IDs

Similar to how we have to create an identifier for our app, and a set of profiles for the apps distribution and development, we are first going to have to create a second identifier and profiles for the extension’s distribution!

Once we have an identifier for both our application and our extension, they both need to add the App Group Capability. While editing the identifier you should specify the group you just created.

Part 6. Shared Database

Now we have an app and extension that both belong to a single app group using a shared container. We can get a URL to this container space through the FileManager with:

FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: “AppGroupId”)

We can use this in a RealmConfiguration to determine how to create our realm instance.

Using this realmConfig, both our app and our extension can get access to an instance of Realm within the same container.

And that’s it! We now have a realm instance in our shared container space. From here you can follow tutorials for specifics on using the Realm database.