In this tutorial we will learn to implement Siri using Intents in Xcode 8.0 with Swift 3. It can be rated as a beginner level tutorial.

Getting started

Open Xcode and create a new project by choosing the Single View Application template. Choose iPhone under “Devices”. Choose Swift as main language.

1

Next, you are presented with the page to set many of the important aspects of your project, particularly your “Product Name” and “Language”, which will be Swift, of course.

Product Name is pretty self-explanatory.  The organization name can be whatever you want, but it probably should the the company or name you are releasing your apps under.

2

Continue by selecting a location where you will save the project and after you click the “Create” button, the files for your project are generated and you are probably looking at your AppDelegate.swift file.

In this tutorial we will focus only on adding SiriKit to your project and changing the UI of the Siri View, so there will not be any changes to the ViewController and it’s swift file. We will also not focus on developing a full fledged messaging app or providing messaging app contacts and data to Siri. Now we will accomplish this basic implementation in following steps:

Step 1: Adding Siri Intent Extension

Go to File > New > Target > Intents Extension. This will add the Siri Intents Extension to your existing project.

3

4

On the next screen you will provide a product name which in our case it will be “Radical Extension”. Make sure you tick the Include UI Extension box if you want to have your own custom view in siri.

5

Step 2: Editing Info.plist

The NSExtension of Siri has 3 methods supported namely INSendMessageIntentINSearchForMessagesIntent and INSetMessageAttributeIntent. In this tutorial we are not searching any existing message intents or setting attributes to it, so we will remove those to items from our Info.plist file of the RadicalExtension folder as show below.

screen-shot-2016-09-23-at-8-24-55-pm

The same procedure needs to be followed for the remove these items from RadicalExtensionUI folder’s Info.plist

Step 3: Remove other Intent functions

We will also remove the intent functions from the IntentHandler.swift code file as we did above. Open IntenHandler.swift file and remove the functions shown below completely:

func handle(searchForMessages intent: INSearchForMessagesIntent, completion: @escaping (INSearchForMessagesIntentResponse) -> Void) {}
func handle(setMessageAttribute intent: INSetMessageAttributeIntent, completion: @escaping (INSetMessageAttributeIntentResponse) -> Void) {}

We will also remove the protocols for these two from the class declaration on top. Remove INSearchForMessagesIntent, INSetMessageAttributeIntent 

class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling {

This is how the class with look now after removing other two.

class IntentHandler: INExtension, INSendMessageIntentHandling {

Step 5: Testing our Initial Progress

So now we need to test whether Siri recognizes our app or not. So just build the project and run it on an actual device. Note: It will not work on simulator as Siri is not supported.

When you run the app on your actual device you will see a blank white screen, don’t worry about that just long press the home button to activate Siri and say something like “Send message using Radical”. At this stage it will prompt to access your Radical app data and give a button to open Siri Settings.

6

You need to turn on the switch located next to your app in Siri Settings.

7

Now again activate Siri by long pressing home button and say something like “Send message using Radical that I’m writing a tutorial on SwiftyOS”

8

You will see something like this in the image above. Wee congrats you have set up Siri for your message application. Now the UI doesn’t seem to be nice enough. For a better user experience there should be same UI as the actual messaging window, the user is always set to imagine a standard UI for certain messages app used daily. Whenever they send a message through Siri, they expect a similar UI view for the Siri Message Box as well. Hence it is also important to design Siri UI view which will be done in sometime.

Step 6: Setting up the Storyboard

Apple provides a different storyboard named MainInterface.storyboard with a Intent ViewController for Siri. We will change the background, add a nice pikachu icon, the message bubble and a UILabel that will show the message. You can get these icons from here and here.
For our project first change the BackgroundView’s color to #fdce42. Second we will add that little pikachu icon that i tweaked a littlebit(Credits: Aki) using UIImageView. Third add that message bubble using UIImageView as per your convenience. Last add a UILabel on top of the message bubble image view. Note: Add constraints accordingly to all the views for different device sizes. It should look something like this:

9

Step 7: Setting up IntentHandler file

Open the IntentHandler file from left navigationbar and change the  resolveRecipients() and resolveContent() functions to the following:

// MARK: - INSendMessageIntentHandling
    
    func resolveRecipients(forSendMessage intent: INSendMessageIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
        let notRequired = INPersonResolutionResult.notRequired()
        completion([notRequired])
    }
    
    func resolveContent(forSendMessage intent: INSendMessageIntent, with completion: @escaping (INStringResolutionResult) -> Void) {
        if let text = intent.content, !text.isEmpty {
            completion(INStringResolutionResult.success(with: text))
        } else {
            completion(INStringResolutionResult.needsValue())
        }
    }

In the resolveRecipients function we removed the recipients results array and initialization. What this does is it checks whether there is any recipient value for the message or no and accordingly prompt the user for a value. It also has a switch case which is activated if there are more then one recipients with same value, for eg. same first name. So when I say “Send a message to Jon using Radical” and if there is more than one person named Jon in the contacts then it provide a tableview with all possible Jon’s to select a single user. In our case we don’t have a full fledged message app nor any contacts, so we rewrite it to personResolutionResult not required and complete anyway.

For the resolveContent function it remains the same where it checks whether the user has provided some content for the message. If content is provided then complete with a success method passing the message and if not provided then Siri will prompt the user to provide content for the message.

The handle function handles the actual app logic for sending the message to the servers and eventually to other person’s device.

Now if you run the app in current position, you will see your custom ui view in siri with a standard messaging siri ui provided by apple attached at the bottom. We need to remove that view and use just our ui view. For achieving this we set a value for the variable displaysMessage to true which indicates the system that we have our own view and would like to remove the standing messaging view.

To do this open the IntentViewController.swift file from the left navigationbar in the RadicalExtensionUI folder and add this line of code:

//Displays my custom message UI
    
    var displaysMessage: Bool {
        return true
    }

Now we also link the UILabel that we had set while setting up the storyboard to our IntentViewController class. To do this, open the storyboard for the Siri view and an assistant editor. Press ctrl+drag the UILabel to the assistant editor and drop for linking it as an outlet with name messageLabel.

10

Now in the Confirm (sendMessage: Completion : ) function we will assign the UILabel to the content we received from the user as the text message. The function will look somewhat like this:

// Prepare your view controller for the interaction to handle.
    func configure(with interaction: INInteraction!, context: INUIHostedViewContext, completion: ((CGSize) -> Void)!) {
        // Do configuration here, including preparing views and calculating a desired size for presentation.
        
        let intent = interaction.intent as! INSendMessageIntent
        messageLabel.text = intent.content
        
        if let completion = completion {
            completion(self.desiredSize)
        }
    }

In the code above we create a constant variable intent which stores the INSendMessageIntent interaction content in it. We then assign the label text to intent.content for the message string.

This was the last piece of code to be added and voila! you are done with the basic siri implementation to your messaging application.

Running the App

So now you run the app with the big “Play” button in the top left of Xcode.  You then need to set actual iOS device to run the app on (requires a paid developer license). I used my iPhone 7 for this simulation.

Then wait a bit until the code is compiled and the binaries are installed on the device. Once the app is open on your device,  long press the home button and say “Send a message using Radical saying code is available on GitHub” and you will see a nice message box as shown below. 

13

Here is the source code on Github for the tutorial above !

I hope you found this article helpful.  If you did, please don’t hesitate to share this post on Twitter or your social media of choice.  The blog is still pretty new, and every share helps.  Of course, if you have any questions, don’t hesitate to contact me on Twitter @swifty_os, and I’ll see what I can do.  Thanks!

Advertisements