WWDC Quick Look 💓 By SwiftGGTeam
Implement App Shortcuts with App Intents

Implement App Shortcuts with App Intents

Watch original video

Highlight

The App Intents framework of iOS 16 allows developers to define App Shortcuts with pure Swift code, without the need for additional metadata files, and is automatically available in Siri, Spotlight and Shortcuts apps after installation.

Core Content

In the past, users would need to click the “Add to Siri” button or manually set it up in the Shortcuts app to use your intent. App Shortcuts removes this barrier—Intents are immediately available in Siri, Spotlight, and Shortcuts apps as soon as the app is installed. (01:02)

App Intents is a new Swift-only framework where all definitions are done in Swift source code and no separate metadata files are required. (02:57) This brings several benefits: no code generation step, no need to switch between the source code editor and the metadata editor, easier code review, and easier resolution of merge conflicts.

Take a meditation app as an example. Previously, users had to open the app, log in, and find the meditation session they wanted to listen to. With App Shortcuts, users can simply say “start meditating” to start the default session. (02:13)

Detailed Content

Basic App Intent

Intent is an implementationAppIntentA Swift struct for a protocol, requiring only two things: a header andperformmethod. (03:44)

import AppIntents

struct StartMeditationIntent: AppIntent {
    static let title: LocalizedStringResource = "Start Meditation Session"

    func perform() async throws -> some IntentResult & ProvidesDialog {
        await MeditationService.startDefaultSession()
        return .result(dialog: "Okay, starting a meditation session.")
    }
}

Key points:

  • titleUsed to display this intent in the Shortcuts app -perform()It is async and can perform asynchronous operations
  • return.result(dialog:)Show feedback to users
  • If the application is localized, the dialog string also needs to be localized

Create App Shortcut

Having Intent is not enough, it needs to be packaged into App Shortcut. accomplishAppShortcutsProviderProtocol: (05:31)

import AppIntents

struct MeditationShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: StartMeditationIntent(),
            phrases: [
                "Start a \(.applicationName)",
                "Begin \(.applicationName)",
                "Meditate with \(.applicationName)",
                "Start a session with \(.applicationName)"
            ]
        )
    }
}

Key points:

  • use\(.applicationName)Instead of hardcoding the app name, Siri automatically inserts the main app name and configured synonyms
  • Provides multiple phrase variations to cover different ways users might say it
  • Maximum of 10 App Shortcuts per app, but most apps only require a few
  • Phrases need to be localized to all languages supported by the app

Custom Snippet view

By default, Siri displays a universal view when running an intent. You can return a custom SwiftUI view to make it more informative. (07:40)

func perform() async throws -> some ProvidesDialog & ShowsSnippetView {
    await MeditationService.startDefaultSession()

    return .result(
        dialog: "Okay, starting a meditation session.",
        view: MeditationSnippetView()
    )
}

Key points:

  • Custom views use SwiftUI, which uses the same view technology as Widgets
  • No need to create UI extension separately
  • Views cannot contain interactions or animations (same restrictions as Widgets)
  • Custom UI can be displayed in three stages: value confirmation, Intent confirmation, and after Intent completion

Add parameters

To allow the user to specify a specific meditation session type, parameters need to be added. First define the parameter type and implementAppEntityProtocol: (10:09)

import AppIntents

struct MeditationSession: AppEntity {
    let id: UUID
    let name: LocalizedStringResource

    static var typeDisplayName: LocalizedStringResource = "Meditation Session"
    var displayRepresentation: AppIntents.DisplayRepresentation {
        DisplayRepresentation(title: name)
    }

    static var defaultQuery = MeditationSessionQuery()
}

Then implement the query protocol so that the App Intents framework can find entities based on identifiers: (10:55)

struct MeditationSessionQuery: EntityQuery {
    func entities(for identifiers: [UUID]) async throws -> [MeditationSession] {
        return identifiers.compactMap { SessionManager.session(for: $0) }
    }
}

Add parameters in Intent: (11:16)

struct StartMeditationIntent: AppIntent {
    @Parameter(title: "Session Type")
    var sessionType: SessionType?

    // ...
}

Prompt user to select value

If the user does not provide a parameter value, you can proactively prompt it. App Intents supports three prompt types: disambiguation (select from a fixed list), value prompt (open-ended value), and confirmation (validate a specific value). (12:14)

func perform() async throws -> some ProvidesDialog {
    let sessionToRun = self.session ?? try await $session.requestDisambiguation(
        among: SessionManager.allSessions,
        dialog: IntentDialog("What session would you like?")
    )

    await MeditationService.start(session: sessionToRun)
    return .result(
        dialog: "Okay, starting a \(sessionToRun.name) meditation session."
    )
}

Key points:

  • use$session.requestDisambiguationLet the user choose from a fixed list
  • App Intents will be used for each sessiondisplayRepresentationFormat list items
  • After the user selects, the selected item will be returned toperformmethod
  • Hints can slow down interaction, don’t overuse them

Parameterized phrase

Let the user specify parameter values ​​directly in the initial command, such as “Start a calming meditation.” This requires three steps: (15:27)

The first step is to implement it in QuerysuggestedEntities()

struct MeditationSessionQuery: EntityQuery {
    func entities(for identifiers: [UUID]) async throws -> [MeditationSession] {
        return identifiers.compactMap { SessionManager.session(for: $0) }
    }

    func suggestedEntities() async throws -> [MeditationSession] {
        return SessionManager.allSessions
    }
}

Key points: This method must be implemented, otherwise the parameterized phrase will not be generated.

The second step is to notify the App Intents parameter value changes at the model layer: (16:34)

class SessionModel {
    @Published
    var sessions: [MeditationSession] = []
    private var cancellable: AnyCancellable?

    init() {
        self.cancellable = $sessions.sink { _ in
            MeditationShortcuts.updateAppShortcutParameters()
        }
    }
}

Key points:

  • updateAppShortcutParameters()Is a method provided by the App Intents framework
  • After the call, the framework will re-query the entity list and update the parameterized phrase
  • Usually called after getting a new session from the server

The third step is to add a phrase with parameters in App Shortcut: (17:09)

struct MeditationShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: StartMeditationIntent(),
            phrases: [
                "Start a \(.applicationName)",
                "Begin \(.applicationName)",
                "Meditate with \(.applicationName)",
                "Start a \($session) session with \(.applicationName)",
                "Begin a \($session) session with \(.applicationName)",
                "Meditate on \($session) with \(.applicationName)"
            ]
        )
    }
}

Key points:

  • use\($session)Reference parameters in the intent
  • The framework will combine the parameter value list with the phrase to generate all variations
  • The display text for the parameter value comes fromDisplayRepresentationoftitle

Discoverability

App Shortcuts are available right out of the box, but users need to know they exist. (17:55)

  • Siri Tip: Display at the right time in the application, supported by both SwiftUI and UIKit, with multiple styles
  • ShortcutsLink: Jump to the list of all shortcuts of this application in the Shortcuts application
  • Siri Active Recommendation: Automatically recommend when users ask “What can I do here?”

Notes

App Shortcuts may be run before the app is first launched. (20:36) If the app requires login, the Intent should fail gracefully, prompting the user to log in first. Parameterized phrases are not available until the application first starts and the framework is notified, so it is recommended to keep at least a few non-parameterized phrases.

Core Takeaways

1. Add zero-configuration voice portal for high-frequency operation

Find out what actions users do in your app every day, and use App Shortcuts to provide one-sentence insights. For example, “Start a run” in fitness apps and “Record an expense” in accounting apps. The implementation cost is very low - a single Intent struct and an AppShortcutsProvider make the functionality available in Siri and Spotlight.

2. Use parameterized phrases to reduce interaction steps

If your app has fixed categories of content (such as playlists, favorite restaurants, frequently used rooms), make the category name a parameter and let the user say “play my running playlist” instead of “play music” and then be asked “what to play.” accomplishsuggestedEntities()and called when the data changesupdateAppShortcutParameters()That’s it.

3. Strategically display Siri Tips within the app

Don’t have random pop-ups. Select the moment when the user may want to repeat it quickly after completing an operation, such as displaying the tip “Next time you can say ‘check my order’” after placing an order manually. Use it directly in SwiftUISiriTipView, UIKit uses the corresponding view. Support closing callbacks and recording user preferences to avoid repeated interruptions.

4. Design graceful degradation for unlogged status

App Shortcuts may be triggered when the user has never opened the app. existperform()Check the necessary status (such as login), and if the conditions are not met, return a friendly dialog to guide the user to open the application to complete the settings, instead of crashing or failing silently.

Comments

GitHub Issues · utterances