Give your simulator superpowers

RocketSim: An Essential Developer Tool
as recommended by Apple

Implementing Siri support using NSUserActivity, intents and shortcuts

Siri support can be added using an Intent and an IntentUI extension. This adds quite some overhead and is not always the easiest way in a big project, as you need shared logic between the main app and the extension.

A much easier way to implement Siri support is by using NSUserActivity.

Asking Siri to open a page in your app

In this example, we’re implementing Siri support for opening a specific board in your app.

Start by adding the Open_board shortcut to your info.plist for the NSUserActivityTypes key.

Siri Shortcut added to the Info.plist
Siri Shortcut added to the Info.plist

After that, create an extension for the BoardDetailViewController which we like to open using Siri. For this, we need to import the Intents framework to make use of the suggestedInvocationPhrase property.

extension BoardDetailViewController {
    func activateActivity(using board: Board) {
        userActivity = NSUserActivity(activityType: "Open_board")
        let title = "Open board \(board.title)"
        userActivity?.title = title
        userActivity?.userInfo = ["id": board.identifier]
        userActivity?.suggestedInvocationPhrase = title
        userActivity?.isEligibleForPrediction = true
        userActivity?.persistentIdentifier = board.identifier
    }
}

This method needs to be called in the viewDidAppear method:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    activateActivity(using: board)
}

We’ve set a few properties:

  • userActivity
    This is an existing property on UIViewController and indicates that the app is currently performing a user activity.
  • userActivity.userInfo
    We set any needed information for deeplink to the page upon handling the Siri action. More about this later.
  • userActivity.suggestedInvocationPhrase
    This is the suggested sentence which is shown after “You can say something like…”
  • userActivity?.persistentIdentifier
    This unique identifier is needed to make it possible to delete the activity eventually.

Stay updated with the latest in Swift

The 2nd largest newsletter in the Apple development community with 18,571 developers. Don't miss out – Join today:


Presenting the Add Voice Shortcut ViewController

To make it possible for your user to record a custom shortcut, we’re going to present the INUIAddVoiceShortcutViewController which is available after importing the IntentsUI framework. In our example, we’re creating a button in our UI which executes the presentAddOpenBoardToSiriViewController method.

extension BoardDetailViewController {
    func presentAddOpenBoardToSiriViewController() {
        guard let userActivity = self.userActivity else { return }
        let shortcut = INShortcut(userActivity: userActivity)
        let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut)
        viewController.modalPresentationStyle = .formSheet
        viewController.delegate = self
        present(viewController, animated: true, completion: nil)
    }
}

extension BoardDetailViewController: INUIAddVoiceShortcutViewControllerDelegate {
    func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) {
        controller.dismiss(animated: true)
    }

    func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) {
        controller.dismiss(animated: true)
    }
}

This will show a native iOS view with a record button for the user to create the custom Shortcut.

Add to Siri support with a recording button
Add to Siri support with a recording button

Handling an incoming shortcut

Whenever the Open Board shortcut is triggered it will open your app with the continue user activity AppDelegate method. This is where you have to match the activity with our Siri activity and open the specific page. In our example, we’re starting the deeplink action to the requested board.

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {

    if userActivity.activityType == "Open_board", let parameters = userActivity.userInfo as? [String: String] {
        try? BoardDeeplinkAction(parameters: parameters, context: persistentContainer.viewContext).execute()
        return true
    }
    return false
}

And that’s about it!

Eligible for prediction as a bonus

That’s right, eligible for prediction. We get some extra functionality for free, as the activity will be used throughout the system to predict a certain user flow. If the user is often opening the Amsterdam board in this example, it’s likely to show up in Siri suggestions.

Siri support for predictions
Siri support for predictions