In this article

Implementing SiriKit in Xamarin.iOS

05/03/2018

30 minutes to read

Contributors

In this article

This article covers the steps required to implement SiriKit support in a Xamarin.iOS apps.

New to iOS 10, SiriKit allows a Xamarin.iOS app to provide services that are accessible to the user using Siri and the Maps app on an iOS device. This article covers the steps required to implement SiriKit support in the Xamarin.iOS apps by adding the required Intents Extensions, Intents UI Extensions and Vocabulary.

Siri works with the concept of Domains, groups of know actions for related tasks. Each interaction that the app has with Siri must fall into one of its known service Domains as follows:

Audio or video calling.

Booking a ride.

Managing workouts.

Messaging.

Searching photos.

Sending or receiving payments.

When the user makes a request of Siri involving one of the App Extension's services, SiriKit sends the extension an Intent object that describes the user's request along with any supporting data. the App Extension then generates the appropriate Response object for the given Intent, detailing how the extension can handle the request.

This guide will present a quick example of including SiriKit support into an existing app. For the sake of this example, we'll be using the fake MonkeyChat app:

MonkeyChat keeps its own contact book of the user's friends, each associated with a screen name (like Bobo for example), and allows the user to send text chats to each friend by their screen name.

Extending the App with SiriKit

Intents Extension - Verifies the users responses, confirms the app can handle the request and actually performs the task to fulfill the user's request.

Intents UI Extension - Optional, provides a custom UI to the responses in the Siri Environment and can bring the apps UI and branding into Siri to enrich the user's experience.

App - Provides the App with User specific vocabularies to assist Siri in working with it.

All of these elements and the steps to include them in the app will be covered in detail in the sections below.

Preparing the App

SiriKit is built on Extensions, however, before adding any Extensions to the app, there are a few things that the developer needs to do to help with the adoption of SiriKit.

Moving Common Shared Code

First, the developer can move some of the common code that will be shared between the app and the extensions into either Shared Projects, Portable Class Libraries (PCLs) or Native Libraries.

The Extensions will need to be able to do all of the things that the app does. In the terms of the sample MonkeyChat app, things like finding contacts, adding new contacts, send messages and retrieve message history.

By moving this common code into a Shared Project, PCL or Native Library it makes it easy to maintain that code in one common place and ensures that the Extension and the parent app provide uniform experiences and functionality for the user.

In the case of the example app MonkeyChat, the data models and processing code such as network and database access will be moved into a Native Library.

Right-click on the Solution Name in the Solution Pad and select Add > New Project...:

Select iOS > Library > Class Library and click the Next button:

Enter MonkeyChatCommon for the Name and click the Create button:

Right-click on the References folder of the main app in the Solution Explorer and select Edit References.... Check the MonkeyChatCommon project and click the OK button:

In the Solution Explorer, drag the common shared code from the main app to the Native Library.

In the case of MonkeyChat, drag the DataModels and Processors folders from the main app into the Native Library:

Start Visual Studio and open the MonkeyChat app.

Right-click on the Solution Name in the Solution Explorer and select Add > New Project....

Select Visual C# > Shared Project and click the Next button:

Enter MonkeyChatCommon for the Name and click the Create button.

Right-click on the References folder of the main app in the Solution Explorer and select Edit References.... Check the MonkeyChatCommon project and click the OK button:

In the Solution Explorer, drag the common shared code from the main app to the Shared Project.

In the case of MonkeyChat, drag the DataModels and Processors folders from the main app into the Native Library.

Edit any of the files that were moved to the Native Library and change the namespace to match that of the library. For example, changing MonkeyChat to MonkeyChatCommon:

using System;
namespace MonkeyChatCommon
{
/// <summary>
/// A message sent from one user to another within a conversation.
/// </summary>
public class MonkeyMessage
{
public MonkeyMessage ()
{
}
...
}
}

Next, go back to the main app and add a using statement for the Native Library's namespace anywhere the app uses one of the classes that have been moved:

Architecting the App for Extensions

Typically, an app will sign up for multiple Intents and the developer needs to ensure that the app is architected for the appropriate number of Intent Extensions.

In the situation where an app requires more than one Intent, the developer has the option of placing all of its Intent handling in one Intent Extension or creating a separate Intent Extension for each Intent.

If choosing to create a separate Intent Extension for each Intent, the developer could end up duplicating a large amount of boilerplate code in each extension and create a large amount of processor and memory overhead.

To help choose between the two options, see if any of the Intents naturally belong together. For example, an app that made audio and video calls might want to include both of those Intents in a single Intent Extension as they are handling similar tasks and could provide the most code reuse.

For any Intent or group of Intents that don't fit into an existing group, create a new Intent Extension in the app's solution to contain them.

Setting the Required Entitlements

Any Xamarin.iOS app that includes SiriKit integration, must have the correct entitlements set. If the developer doesn't set these required entitlements correctly, they will not be able to install or test the app on real iOS 10 (or greater) hardware, which is also requirement since the iOS 10 Simulator doesn't support SiriKit.

Correctly Provisioning the App

Because of the strict security that Apple has placed around the SiriKit framework, any Xamarin.iOS app that implements SiriKit must have the correct App ID and Entitlements (see section above) and must be signed with a proper Provisioning Profile.

Testing SiriKit only works on a real iOS 10 Hardware Device and not in the iOS 10 Simulator. If having issues installing a SiriKit enabled Xamarin.iOS app on real hardware, ensure that the required Entitlements, App ID, Signing Identifier and Provisioning Profile have been correctly configured in both Apple's Developer Portal and Visual Studio for Mac.

Requesting Siri Authorization

Before the app adds any User Specific Vocabulary or the Intents Extensions connects to Siri, it must requests authorization from the user to access Siri.

Edit the app's Info.plist file, switch to the Source view and add the NSSiriUsageDescription key with a string value describing how the app will use Siri and what types of data will be sent. For example, the MonkeyChat app might say "MonkeyChat contacts will be sent to Siri":

Edit the app's Info.plist file and add the NSSiriUsageDescription key with a string value describing how the app will use Siri and what types of data will be sent. For example, the MonkeyChat app might say "MonkeyChat contacts will be sent to Siri":

Call the RequestSiriAuthorization method of the INPreferences class when the app first starts. Edit the AppDelegate.cs class and make the FinishedLaunching method look like the following:

The first time this method is called, an alert is displayed prompting the user to allow the app to access Siri. The message that the developer added to the NSSiriUsageDescription above will be displayed in this alert. If the user initially denies access, they can use the Settings app to grant access to the app.

At any time, the app can check the app's ability to access Siri by calling the SiriAuthorizationStatus method of the INPreferences class.

Localization and Siri

On an iOS device, the user is able to select a language for Siri that is different then the system default. When working with localized data, the app will need to use the SiriLanguageCode method of the INPreferences class to get the language code from Siri. For example:

Adding User Specific Vocabulary

The User Specific Vocabulary is going to provide words or phrases that are unique to individual users of the app. These will be provided at runtime from the main app (not the App Extensions) as an ordered set of terms, ordered in a most significant usage priority for the users, with the most important terms at the start of the list.

User Specific Vocabulary must belong to one of the following categories:

Contact Names (that are not managed by the Contacts framework).

Photo Tags.

Photo Album Names.

Workout Names.

When selecting terminology to register as custom vocabulary, only choose terms that might be misunderstood by someone not familiar with the app. Never register common terms such as "My Workout" or "My Album". For example, the MonkeyChat app will register the nicknames associated with each contact in the user's address book.

The app provides the User Specific Vocabulary by calling the SetVocabularyStrings method of the INVocabulary class and passing in a NSOrderedSet collection from the main app. The app should always call the RemoveAllVocabularyStrings method first, to remove any existing terms before adding new ones. For example:

Siri treats custom vocabulary as hints and will incorporate as much of the terminology as possible. However, space for custom vocabulary is limited making it important to register only the terminology that might be confusing, therefore keeping the total number of registered terms to a minimum.

Adding App Specific Vocabulary

The App Specific Vocabulary defines the specific words and phrases that will be known to all of the app's users, such as vehicle types or workout names. Because these are part of the application, they are defined in a AppIntentVocabulary.plist file as part of the main app bundle. Additionally, these words and phrases should be localized.

App Specific Vocabulary terms must belong to one of the following categories:

Double-click the AppIntentVocabulary.plist file in the Solution Explorer to open it for editing.

Click the + to add a key, set the Name to ParameterVocabularies and the Type to Array:

Expand ParameterVocabularies and click the + button and set the Type to Dictionary:

Click the + to add a new key, set the Name to ParameterNames and the Type to Array:

Click the + to add a new key with the Type of String and the value as one of the available Parameter Names. For example, INStartWorkoutIntent.workoutName:

Add the ParameterVocabulary key to the ParameterVocabularies key with the Type of Array:

Add a new key with the Type of Dictionary:

Add the VocabularyItemIdentifier key with the Type of String and specify a unique ID for the term:

Add the VocabularyItemSynonyms key with the Type of Array:

Add a new key with the Type of Dictionary:

Add the VocabularyItemPhrase key with the Type of String and the term the app are defining:

Add the VocabularyItemPronunciation key with the Type of String and the phonetic pronunciation of the term:

Add the VocabularyItemExamples key with the Type of Array:

Add a few String keys with example uses of the term:

Repeat the above steps for any other custom terms the app need to define.

Collapse the ParameterVocabularies key.

Add the IntentPhrases key with the Type of Array:

Add a new key with the Type of Dictionary:

Add the IntentName key with the Type of String and Intent for the example:

Add the IntentExamples key with the Type of Array:

Add a few String keys with example uses of the term:

Repeat the above steps for any Intents the app need to provide example usage of.

Important

The AppIntentVocabulary.plist will be registered with Siri on the test devices during development and it might take some time for Siri to incorporate the custom vocabulary. As a result, the tester will need to wait several minutes before attempting to test App Specific Vocabulary when it has been updated.

Creating the Extension

Right-click on the Solution Name in the Solution Pad and select Add > Add New Project....

From the dialog box select iOS > Extensions > Intent Extension and click the Next button:

Next enter a Name for the Intent Extension and click the Next button:

Finally, click the Create button to add the Intent Extension to the apps solution:

In the Solution Explorer, right-click on the References folder of the newly created Intent Extension. Check the name of the common shared code library project (that the app created above) and click the OK button:

Right-click on the Solution Name in the Solution Explorer and select Add > Add New Project....

In the Solution Explorer, right-click on the References folder of the newly-created Intents Extension and choose Add > Reference. Check the name of the common shared code library project (that the app created above) and click the OK button:

Configuring the Info.plist

For each of the Intents Extensions that have added to the app's solution, must be configured in the Info.plist files to work with the app.

Just like any typical App Extension, the app will have the existing keys of NSExtension and NSExtensionAttributes. For an Intents Extension there are two new attributes that must be configured:

IntentsSupported - Is required and consists of an array of Intent Class names that the app wants to support from the Intent Extension.

IntentsRestrictedWhileLocked - Is an optional key for the app to specify the extension's lock screen behavior. It consists of an array of Intent Class names that the app wants to require the user to be logged in to use from the Intent Extension.

To configure the Intent Extension's Info.plist file, double-click it in the Solution Explorer to open it for editing. Next, switch to the Source view then expand the NSExtension and NSExtensionAttributes keys in the editor:

If the app optionally requires that the user be logged on to the device to use a given intent, expand the IntentRestrictedWhileLocked key and add the Class names of the Intents that have restricted access. For the example MonkeyChat app, the user must be logged in to send a chat message so we have added INSendMessageIntent:

Configuring the Main Class

Next, the developer will need to configure the main class that acts as the main entry point for the Intent Extension into Siri. It must be a subclass of INExtension which conforms to the IINIntentHandler delegate. For example:

There is one solitary method that the app must implement on the Intent Extension main class, the GetHandler method. This method is passed an Intent by SiriKit and the app must return an Intent Handler that matches the type of the given Intent.

Since the example MonkeyChat app only handles one intent, it is returning itself in the GetHandler method. If the extension handled more than one intent, the developer would add a class for each intent type and return an instance here based on the Intent passed to the method.

Handling the Resolve Stage

The Resolve Stage is where the Intent Extension will clarify and validate parameters passed in from Siri and have been set via the user's conversation.

For each parameter that gets sent from Siri, there is a Resolve method. The app will need to implement this method for every parameter that the app might need Siri's help to get the correct answer from the user.

In the case of the example MonkeyChat app, the Intent Extension will require a one or more recipients to send the message to. For each recipient in the list, the extension will need to do a contact search that can have the following outcome:

Exactly one matching contact is found.

Two or more matching contacts are found.

No matching contacts are found.

Additionally, MonkeyChat requires content for the body of the message. If the user has not provided this, Siri needs to prompt the user for the content.

The Intent Extension will need to gracefully handle each of these cases.

Handling the Confirm Stage

The Confirm Stage is where the Intent Extension checks to see that it has all of the information to fulfill the user's request. The app wants to send confirmation along will all the supporting details of what is about to happen to Siri so it can be confirmed with the user that this is the intended action.

Adding an Intents UI Extension

The optional Intents UI Extension presents the opportunity to bring the app's UI and branding into the Siri experience and make the users feel connected to the app. With this extension the app can bring the brand as well as visual and other information into the transcript.

Just like the Intents Extension, the developer will do the following step for the Intents UI Extension:

Finally, click the Create button to add the Intent Extension to the apps solution:

In the Solution Explorer, right-click on the References folder of the newly created Intent Extension. Check the name of the common shared code library project (that the app created above) and click the OK button:

Right-click on the Solution Name in the Solution Explorer and select Add > Add New Project...

In the Solution Explorer, right-click on the References folder of the newly created Intent Extension. Check the name of the common shared code library project (that the app created above) and click the OK button.

Configuring the Info.plist

Configure the Intents UI Extension's Info.plist file to work with the app.

Just like any typical App Extension, the app will have the existing keys of NSExtension and NSExtensionAttributes. For an Intents Extension there is one new attribute that must be configured:

IntentsSupported is required and consists of an array of Intent Class names that the app want to support from the Intent Extension.

To configure the Intent UI Extension's Info.plist file, double-click it in the Solution Explorer to open it for editing. Next, switch to the Source view then expand the NSExtension and NSExtensionAttributes keys in the editor:

To configure the Intent UI Extension's Info.plist file, double-click it in the Solution Explorer to open it for editing. Expand the NSExtension and NSExtensionAttributes keys in the editor:

Expand the IntentsSupported key and add the name of any Intent Class this extension will support. For the example MonkeyChat app, it supports the INSendMessageIntent:

Configuring the Main Class

Configure the main class that acts as the main entry point for the Intent UI Extension into Siri. It must be a subclass of UIViewController which conforms to the IINUIHostedViewController interface. For example:

Siri will pass a INInteraction class instance to the Configure method of the UIViewController instance inside of the Intent UI Extension.

The INInteraction object provides three key pieces of information to the extension:

The Intent object being processed.

The Intent Response object from the Confirm and Handle methods of the Intent Extension.

The Interaction State that defines the state of the interaction between the app and Siri.

The UIViewController instance is the principle class for the interaction with Siri and because it inherits from UIViewController, it has access to all of the features of UIKit.

When Siri calls the Configure method of the UIViewController it passes in a View Context stating that the View Controller will either be hosted in a Siri Snippit or Maps Card.

Siri will also pass in a completion handler that the app need to return the desired size of the view once the app have finished configuring it.

Design the UI in iOS Designer

Layout the Intents UI Extension's user interface in the iOS Designer. Double-click the extension's MainInterface.storyboard file in the Solution Explorer to open it for editing. Drag in all of the required UI elements to build out the User Interface and save the changes.

Important

While it is possible to add interactive elements such as UIButtons or UITextFields to the Intent UI Extension's UIViewController, these are strictly forbidden as the Intent UI in non-interactive and the user will not be able to interact with them.

Wire-Up the User Interface

With the Intents UI Extension's User Interface created in iOS Designer, edit the UIViewController subclass and override the Configure method as follows:

Overriding the Default Siri UI

The Intents UI Extension will always be displayed along with other Siri content such as the app icon and name at the top of the UI or, based on the Intent, buttons (like Send or Cancel) may be displayed at the bottom.

There are a few instances where the app can replace the information that Siri is displaying to the user by default, such as messaging or maps where the app can replace the default experience with one tailored to the app.

If the Intents UI Extension needs to override elements of the default Siri UI, the UIViewController subclass will need to implement the IINUIHostedViewSiriProviding interface and opt-in to displaying a particular interface element.

Add the following code to the UIViewController subclass to tell Siri that the Intent UI Extension is already displaying the message contents:

public bool DisplaysMessage {
get {return true;}
}

Considerations

Apple suggests that the developer take the following considerations into account when designing and implementing the Intent UI Extensions:

Be Conscious of Memory Usage - Because Intent UI Extensions are temporary and only shown for a short time, the system imposes tighter memory constraints than are used with a full app.

Consider Minimum and Maximum View Sizes - Ensure that the Intent UI Extensions looks good on every iOS device type, size and orientation. Additionally, the desired size that the app sends back to Siri might not be able to be granted.

Use Flexible and Adaptive Layout Patterns - Again, to ensure that the UI looks great on every device.

Summary

This article has covered SiriKit and shown how it can be added to the Xamarin.iOS apps to provide services that are accessible to the user using Siri and the Maps app on an iOS device.