Overview
Implement App Shortcuts
App Shortcut은 App Intent 프레임워크로 구현한다.
별도의 메타데이터 파일이 아닌, Swift 코드로 정의한다.
AppShortCutsProvider를 통해서 Intent를 단축어로 변환하는데 필요한 구문과 데이터를 제공한다.
Intent 구현
// 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.")
}
}
shortcut으로 구현하기
// 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)"
]
)
}
}
이렇게 구현된 App Shortcut은 Siri와 Spotlight등에서 쉽게 찾을 수 있다.
Shortcut실행 결과로 커스텀 뷰 띄우기
SwiftUI 뷰를 사용한다
인터렉션이나 애니매이션을 포함할 수 없다.
총 3구간에서 커스텀 뷰를 적용할 수 있다.
예시(after run intent)
// 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()
)
}
Add parameters
entity 구현
// 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()
}
// 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) }
}
}
정의한 Entity를 Intent의 매개 변수로 쓰기
// 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?
// ...
}
매개변수를 사용자에게 요구하기
어떤 것을 원하는지 후속으로 질문할 수 있게 한다.
Disambiguation: 고정 목록에서 선택.
Value Prompt: 정수, 문자열 등의 열린 값을 요청하는 데 좋다.
Confimation: 실제 실행 전 한번 더 확인 시키는 용도
프롬프트가 너무 많으면 속도가 느려지고 유저가 답답할 수 있으니 적절하게 사용해야 한다.
코드로 구현(Disambiguation)
// 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."
)
}
매번 묻는 건 귀찮으니 몇가지 매개변수를 기본으로 제공해주면 좋겠다.
Query에서 suggestedResults() 메소드를 구현해야 한다.
// 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
}
}
사용 가능한 목록이 변경되면, AppIntent 프레임워크에 알려야 한다
// 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()
}
}
// ...
}
Parameter를 받을 수 있는 새로운 구문을 추가해야 한다.
// 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