Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2022 App Services

WWDC22 · 23 min · App Services

Implement App Shortcuts with App Intents

Discover how you can create Shortcuts in your app with zero user setup. We’ll show you how App Intents can help you present custom Shortcuts views, and explore how you can add support for parameterized phrases to allow people to quickly express their intent. We’ll also share how you can make your App Shortcuts discoverable with a Siri Tip, and Shortcuts links. To get the most out of this session, we recommend a basic familiarity with SwiftUI.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 11 snippets

Implement an AppIntent swift · at 3:43 ↗
// StartMeditationIntent creates a meditation session.

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.")
    }
}
Create an AppShortcutsProvider swift · at 5:31 ↗
// An AppShortcut turns an Intent into a full fledged shortcut
// AppShortcuts are returned from a struct that implements the AppShortcuts
// protocol

import AppIntents

struct MeditationShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: StartMeditationIntent(),
            phrases: ["Start a \(.applicationName)"]
        )
    }
}
Provide multiple phrases swift · at 6:35 ↗
// An AppShortcut turns an Intent into a full fledged shortcut
// AppShortcuts are returned from a struct that implements the AppShortcuts
// protocol

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)"
            ]
        )
    }
}
Provide a dialog and snippet view swift · at 8:54 ↗
// Custom views give your intent more personality
// and can convey more information

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

    return .result(
        dialog: "Okay, starting a meditation session.",
        view: MeditationSnippetView()
    )
}
Implement an AppEntity swift · at 10:09 ↗
// An entity is a type that can be used as a parameter
// for an AppIntent.

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()
}
Query for entities swift · at 10:55 ↗
// Queries allow the App Intents framework to
// look up your entities by their identifier

struct MeditationSessionQuery: EntityQuery {
    func entities(for identifiers: [UUID]) async throws -> [MeditationSession] {
        return identifiers.compactMap { SessionManager.session(for: $0) }
    }
}
Define a parameter swift · at 11:16 ↗
// Adding a parameter to an intent allows you to prompt the user
// to provide a value for the parameter

struct StartMeditationIntent: AppIntent {

    @Parameter(title: "Session Type")
    var sessionType: SessionType?

    // ...

}
Prompt for values swift · at 13:15 ↗
// Prompting for values can be done by calling methods
// on the property's wrapper type.

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."
    )
}
Implement suggestedEntities() swift · at 16:11 ↗
// Queries can provide suggested values for your Entity
// that serve as parameters for App Shortcuts

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
    }
}
Update App Shortcut parameters swift · at 16:34 ↗
// Your app must notify App Intents when your values change
// This is typically best done in your app’s model layer

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

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

    // ...

}
Add parameterized phrases swift · at 17:09 ↗
// Phrases can also contain a single parameter reference

import AppIntents

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)"
            ]
        )
    }
}

Resources