An iOS 10 Example SiriKit Messaging Extension

From Techotopia
Revision as of 15:59, 17 November 2016 by Neil (Talk | contribs) (Seeking Siri Authorization)

Jump to: navigation, search

PreviousTable of ContentsNext
An Introduction to SiriKitAn iOS 10 SiriKit Photo Search Tutorial


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book


The previous chapter covered much of the theory associated with integrating Siri into an iOS app. This chapter will review the example Siri messaging extension that is created by Xcode when a new Intents Extension is added to a project. This will not only show a practical implementation of the topics covered in the previous chapter, but will also provide some more detail on how the integration works. The chapter will also cover the steps required to make use of a UI Extension within an app project.


Contents


Creating the Example Project

Begin by launching Xcode and creating a new Single View Controller project named MySiriDemo using Swift as the programming language.

Enabling the Siri Entitlement

Once the main project has been created the Siri entitlement must be enabled for the project. Select the MySiriDemo target located at the top of the Project Navigator panel so that the main panel displays the project settings. From within this panel, select the Capabilities tab, locate the Siri entry and change the switch setting from Off to On as shown in Figure 101-1:


Xcode 8 ios 10 enable siri entitlement.png

Figure 101-1


Seeking Siri Authorization

In addition to enabling the Siri entitlement, the app must also seek authorization from the user to integrate the app with Siri. This is a two-step process which begins with the addition of an entry to the Info.plist file of the iOS app target for the NSSiriUsageDescription key with a corresponding string value explaining how the app makes use of Siri.

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

Select the Info.plist file, locate the bottom entry in the list of properties and hover the mouse pointer over the item. When the plus button appears, click on it to add a new entry to the list. From within the dropdown list of available keys, locate and select the Privacy – Siri Usage Description option as shown in Figure 102-2:


Xcode 8 ios 10 add siri usage key.png

Figure 101-2

Within the value field for the property, enter a message to display to the user when requesting permission to use speech recognition. For example:

Siri support is used to send and review messages.

In addition to adding the Siri usage description key, a call also needs to be made to the requestSiriAuthorization class method of the INPreferences class. Ideally, this call should be made the first time that the app runs, not only so that authorization can be obtained, but also so that the user learns that the app includes Siri support. For the purposes of this project, the call will be made within the viewDidLoad method of the ViewController class. Edit the ViewController.swift file and modify it to import the Intents framework and to call the requestSiriAuthorization method:

import UIKit
import Intents

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        INPreferences.requestSiriAuthorization({status in
            // Handle errors here
        })
    }
.
.
.
}

Before proceeding, compile and run the app on an iOS device. When the app loads a dialog will appear requesting authorization to use Siri. Select the OK button in the dialog to provide authorization.

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

Adding the Extensions

The next step is to add the Intents Extension to the project ready to begin the SiriKit integration. Select the Xcode File -> New -> Target… menu option and add an Intents Extension to the project. Name the product MySiriDemoIntent and make sure that the Include UI Extension option is selected before clicking on the Finish button. When prompted to do so, activate the build schemes for both the Intents and UI Extensions.

Supported Intents

In order to work with Siri, an extension must specify the intent types it is able to support. These declarations are made in the Info.plist files of the extension folders. Within the Project Navigator panel, select the Info.plist file located in the MySiriDemoIntent folder and unfold the NSExtension -> NSExtensionAttributes section. This will show that the IntentsSupported key has been assigned an array of intent class names:


Xcode 8 siri supported intents messages.png

Figure 101-3


Note that entries are available for intents that are supported and intents that are supported but restricted when the lock screen is enabled. It might be wise, for example, for a payment based intent to be restricted when the screen is locked. As currently configured, the extension supports all of the messaging intent types without restrictions. To support a different domain, change these intents or add additional intents accordingly. For example, a photo search extension might only need to specify INSearchForPhotosIntent as a supported intent.

The supported intent settings are also configured in the Info.plist file contained in the MySiriDemoIntentUI and will also need to be changed if the UI Extension is being used. Note that the intents supported by the Intents Extension do not necessarily have to match those of the UI Extension. This allows the UI Extension to be used only for certain intent types.

Trying the Example

Before exploring the structure of the project it is worth running the app and experiencing the Siri integration. The example simulates searching for and sending messages, so can be safely used without any messages actually being sent.

Make sure that the MySiriDemoIntent option is selected as the run target in the toolbar as illustrated in Figure 101 4 and click on the run button.


Ios 10 select siri extension.png

Figure 101-4

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

When prompted, select Siri as the app within which the extension is to run. When Siri launches experiment with phrases such as the following:

“Send a message with MySiriDemo.”

“Send a message to John with MySiriDemo.”

“Find Messages with MySiriDemo.”

In each case, all of the work involved in understanding the phrases and converting them into structured representations of the request is performed by Siri. All the intent handler needs to do is work with the resulting intent object.

Reviewing the Intent Handler

The Intent Handler is declared in the IntentHandler.swift file in the MySiriDemoIntent folder. Load the file into the editor and note that the class declares that it supports a range of intent handling protocols for the messaging domain:

class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling {
.
.
}

The above declaration declares the class as supporting all three of the intents available in the messaging domain. As an alternative to listing all of the protocol names individually, the above code could have achieved the same result by referencing the INMessagesDomainHandling protocol which encapsulates all three protocols.

If this template were to be repurposed for a different domain, these protocol declarations would need to be replaced. For a payment extension, for example, the declaration might read as follows:

class IntentHandler: INExtension, INSendPaymentIntentHandling, INRequestPaymentIntent {
.
.
.
}

The class also contains the handler method, resolution methods for the intent parameters and the confirm method. The resolveRecipients method is of particular interest since it demonstrates the use of the resolution process to provide the user with a range of options from which to choose when a parameter is ambiguous.

The implementation also contains multiple handle methods for performing tasks for message search, message send and message attribute change intents. Take some time to review these methods before proceeding.

Modifying the UI Extension

The UI Extension provides a way to control the appearance of information when it is displayed within the Siri interface. It also allows an extension to present additional information that would not normally be displayed by Siri or to present information using a visual style that reflects the main app. This is achieved by designing a user interface (also known as a Siri snippet) to be displayed within the Siri interface. Consider the default screen (Figure 101-5) displayed by Siri when it is ready to send a message using the MySiriDemo app:


Ios 10 default siri interface.png

Figure 101-5

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

The blank area at the top of the message panel is the area represented by the UI Extension (had we not requested the UI Extension when the Intents Extension was added, this area would not be present). Specifically, this displays the scene defined in the MainInterface.storyboard file of the MySiriDemoIntentUI extension folder. The lower section of the panel is the default user interface provided by Siri.

To provide a custom user interface using the UI Extension, the user interface needs to be implemented in the MainInterface.storyboard file and code added to the IntentViewController.swift file. The IntentViewController class in this file is a subclass of UIViewController and configured such that it implements the INUIHostedViewControlling protocol.

The UI Extension is only used when information is being presented to the user in relation to an intent type that has been declared as supported in the UI Extension’s Info.plist file. When the extension is used, the configure method of the IntentViewController is called and passed an INInteraction object containing both the NSUserActivity and intent objects associated with the current Siri session. This allows context information about the session to be extracted and displayed to the user via the custom user interface defined in the MainInterface.storyboard file.

Designing the Siri Snippet Scene

For the purposes of this example, the storyboard scene for the UI Extension will be configured to display the content of the message on a white label with a black background. Select the MainInterface.storyboard file and drag and drop a Label object so that it is positioned in the center of the scene. Using the Auto Layout Resolve Auto Layout Issues menu, select the option to Reset to Suggested Constraints.

Select the Label object, display the Attributes Inspector panel and change the color property to white. Next, select the background view and change the background color to black. On completion of these steps, the layout should match Figure 101-6:


Xcode 8 ios 10 siri ui.png

Figure 101-6


Display the Assistant Editor and establish an outlet connection from the Label object named contentLabel. Finally, double-click on the label and delete the default “Label” text.

Modifying the configure Method

The configure method now needs to be modified to detect if the current intent is a send message intent, extract the message content from the intent object and display it on the Label object within the storyboard scene. Edit the IntentViewController.swift file, locate the template configure method and modify it as follows:

func configure(with interaction: INInteraction!, context: INUIHostedViewContext, completion: ((CGSize) -> Void)!) {

    if interaction.intent is INSendMessageIntent {
        let intent = interaction.intent as! INSendMessageIntent
        self.contentLabel.text = intent.content
    }

    if let completion = completion {
        completion(self.desiredSize)
    }
}

The added code simply checks that the intent is of type INSendMessageIntent, extracts the intent from the NSInteraction object and then assigns the message content contained within the intent to the text property of the Label object.

Compile and run the extension and use Siri to prepare a message so that it is ready to be sent. This time, the UI Extension section should appear as shown in Figure 101-7:


Ios 10 siri interface with extension.png

Figure 101-7

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

Clearly the extension user interface is working. There is, however, an issue in that the message content is now displayed twice, once by the UI Extension and once by Siri. A preferable outcome would be for the message only to appear in the UI Extension. This can be achieved using a feature referred to as Siri override control.

Overriding Siri Content

Siri override control defines a system whereby a UI Extension can let Siri know that it will take responsibility for displaying certain types of information, thereby avoiding duplicated content within the Siri user interface. Currently SiriKit only allows maps, message content and payment transactions to be replaced by the UI Extension.

Override control requires that the intent view controller implement the INUIHostingViewSiriProviding protocol together with the methods for the content to be overridden. Available methods are as follows:

  • displaysMap
  • displaysMessage
  • displaysPaymentTransaction

The methods return a Boolean value indicating whether or not the Extension UI will be displaying the content.

In this case, the displaysMessage method needs to be added and implemented such that it returns a true value. Edit the IntentViewController.swift file and implement these changes as follows:

import IntentsUI

class IntentViewController: UIViewController, INUIHostedViewControlling, INUIHostedViewSiriProviding {
.
.
    var displaysMessage: Bool {
        return false
    }
.
.
}

Run the intent extension one last time, prepare a message using Siri and verify that the message content is no longer duplicated by Siri:


Ios 10 siri override control.png

Figure 101-8

Summary

This chapter has provided a walk-through of the sample messaging-based extension provided by Xcode when creating a new Intents Extension. This has highlighted the steps involved in adding both Intents and UI Extensions to an existing project, and enabling and seeking SiriKit integration authorization for the project. The chapter also outlined the steps necessary for the extensions to declare supported intents and provided an opportunity to gain familiarity with the methods that make up a typical intent handler. Finally, the chapter outlined the mechanism for implementing and configuring a UI Extension.


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book



PreviousTable of ContentsNext
An Introduction to SiriKitAn iOS 10 SiriKit Photo Search Tutorial