public: true
title: WWDC 2022/Implement App Shortcuts with App Intents
Date: [[Jun 8th, 2022]]
Conference: [[WWDC 2022]]
Speaker(s): [[Michael Sumner]]
Tags: [[Talks]]
URL:
- ## [[Overview]]
- People use shortcuts to create multi-step workflows
- Before now, someone had to make an app shortcut via Siri or in the Shortcuts app
- In iOS 16
- Available as soon as your app is installed
- App Shortcuts can be run from Shortcuts, Spotlight. and Siri
- **When searching in Spotlight, it will rank right away**
- But not if it launches your app
- ## [[Implement App Shortcuts]]
- [[App Shortcuts]] are built with [[App Intents]]
- [[Swift]] only framework
- App Intents are implemented in Swift
- `AppShortcutsProvider` defines phrases for your [[Shortcuts]]
- **Each app can have a maximum of 10 App Shortcuts**
- Implement an AppIntent
-
```swift
// 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
// 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)"]
)
}
}
```
- Using the token allows Siri to also look for App Name synonyms you’ve configured
- Provide multiple phrases
-
```swift
// 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
- Custom views in App Intents
- Leverage [[SwiftUI]]
- Can’t include interactivity or animations
- Can display custom UI at multiple steps
- To display custom UI, return your view from the intent
-
```swift
// 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()
)
}
```
- Implementing an AppEntity
-
```swift
// 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
// 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
// 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
- 3 types of promps
- **Disambiguation**: Choose from a fixed list
- **Value**: Ask the user for a freeform value like a string or int
- **Confirmation**: Double check with the user about what they mean
- They slow down the conversation, so use sparingly.
-
see: [[WWDC 2022/Design App Intents]]
-
```swift
// 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."
)
}
```
- Parameterized phrases
- App Shortcuts support predefined parameters
- **Example**: "start a *walking* meditation"
- Not meant for open ended values
- Can’t support "Search my diary for x" as an initial query
- Implement `suggestedEntities()`
-
```swift
// 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 whenever your app’s model changes
-
```swift
// 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
// 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)"
]
)
}
}
```
-
- ## Add discoverability
- Natural phrases
- Great phrases are short and memorable
- Consider using your app name as a noun or verb
- App name synonyms are supported
- Siri Tip
- Discoverability is vital for users
- [[Siri Tip]] replaces the [[Add to Siri button]]
- Avaiable in [[SwiftUI]] and [[UIKit]]
- Best placed contextually
- Order status check after placing an order
- Supports dismissal
- Calls a custom closure when tapped, remove it from the layout and don’t show it again until relevant
- Shortcuts Link
- `ShortcutsLink` opens the shortcuts app to a filtered list of your shortcuts
- App Installation
- App Shortcuts appear as soon as your app is installed
- Your intent should fail gracefully if it’s run before the user is logged in
- Parameter values won’t be gathered until you notify App Instents
- If you have no parameterized phrases, the user won’t see them until you run the app
- Siri now supports
- "What can I do here?"
- "What can I do with **AppName**?"
- Ordering determined by the order in your shortcut
- Put best and most-used shortcuts and phrases first in the lists
-