--- id: ios-app-intents-shortcuts title: App Intents — Shortcuts / Siri / Spotlight category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [ios, app-intents, siri, shortcuts, vibe-coding] tech_stack: { language: "Swift / AppIntents", applicable_to: ["iOS"] } applied_in: [] aliases: [App Intents, Siri, Shortcuts, Spotlight, Focus filter, Apple Intelligence] --- # App Intents (iOS 16+) > Siri / Shortcuts / Spotlight / Focus / Action button 을 한 번에. **선언형 Swift 코드만**. iOS 18+ Apple Intelligence 가 자동 사용. 옛 SiriKit / NSUserActivity 보다 단순. ## 📖 핵심 개념 - AppIntent: 사용자가 시작 가능한 액션. - AppEntity: 도메인 객체 (Note / Item / Recipe). - AppShortcutsProvider: 앱 내장 shortcut 등록. - Parameter: 사용자에게 물음 또는 자동. ## 💻 코드 패턴 ### AppEntity ```swift import AppIntents struct NoteEntity: AppEntity, Identifiable { let id: UUID let title: String let body: String static var typeDisplayRepresentation: TypeDisplayRepresentation = "Note" var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(title)") } static var defaultQuery = NoteQuery() } struct NoteQuery: EntityQuery { func entities(for ids: [UUID]) async throws -> [NoteEntity] { Database.notes(ids: ids) } func suggestedEntities() async throws -> [NoteEntity] { Database.recentNotes(limit: 5) } } ``` ### AppIntent ```swift struct CreateNoteIntent: AppIntent { static var title: LocalizedStringResource = "Create Note" static var description = IntentDescription("Create a new note in the app.") @Parameter(title: "Title") var title: String @Parameter(title: "Body", default: "") var body: String @MainActor func perform() async throws -> some IntentResult & ReturnsValue { let note = try await Database.create(title: title, body: body) return .result(value: note) } } ``` ### AppShortcuts ```swift struct AppShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: CreateNoteIntent(), phrases: [ "Create note in \(.applicationName)", "New \(.applicationName) note", ], shortTitle: "Create Note", systemImageName: "square.and.pencil" ) AppShortcut( intent: SearchNotesIntent(), phrases: ["Search \(.applicationName)"], shortTitle: "Search", systemImageName: "magnifyingglass" ) } } ``` ### Open App Intent ```swift struct OpenNoteIntent: AppIntent { static var title: LocalizedStringResource = "Open Note" static var openAppWhenRun: Bool = true @Parameter(title: "Note") var note: NoteEntity @MainActor func perform() async throws -> some IntentResult { Router.shared.navigate(to: .note(id: note.id)) return .result() } } ``` ### Spotlight (CoreSpotlight + AppEntity) ```swift import CoreSpotlight func indexNotes() async { let notes = await Database.allNotes() let items = notes.map { note -> CSSearchableItem in let attrs = CSSearchableItemAttributeSet(contentType: .note) attrs.title = note.title attrs.contentDescription = note.body return CSSearchableItem(uniqueIdentifier: note.id.uuidString, domainIdentifier: "notes", attributeSet: attrs) } try? await CSSearchableIndex.default().indexSearchableItems(items) } // Spotlight tap → handle func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { if userActivity.activityType == CSSearchableItemActionType, let id = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String { Router.shared.navigate(to: .note(id: UUID(uuidString: id)!)) } } ``` ### Focus filter (집중 모드) ```swift struct WorkFocusFilter: SetFocusFilterIntent { static var title: LocalizedStringResource = "Work mode" @Parameter(title: "Show only work projects") var workOnly: Bool func perform() async throws -> some IntentResult { FocusManager.shared.setWorkOnly(workOnly) return .result() } } ``` ### Action button (iPhone 15 Pro+) - Settings → Action Button → Shortcut → 앱의 AppShortcut 선택. ### Widget interactivity (iOS 17+) ```swift struct CreateNoteButton: View { var body: some View { Button(intent: CreateNoteIntent(title: "Quick", body: "")) { Image(systemName: "plus") } } } ``` 위젯에서 직접 intent 실행 — 앱 안 열림. ### iOS 18 Apple Intelligence - AppEntity + AppIntent 기반으로 Siri 가 똑똑하게 사용. - AssistantSchema (예: `.system.intents.search`) 가 새로움. ## 🤔 의사결정 기준 | 기능 | 사용 | |---|---| | Siri / Shortcuts | AppIntent + AppShortcutsProvider | | Spotlight 검색 | CoreSpotlight + AppEntity | | Widget 버튼 | Button(intent:) | | Live Activity 인터랙션 | Same intent | | Focus mode | SetFocusFilterIntent | | Action button | AppShortcut | ## ❌ 안티패턴 - **AppIntent perform 무거움**: timeout. 짧게 + background work 따로. - **Phrases 가 너무 generic**: "Search" 같은 거 — 다른 앱과 충돌. - **localized X**: 다국어 사용자 무시. LocalizedStringResource. - **Open intent + 무 navigation**: 앱만 열림 — 사용자 어색. - **Old SiriKit + AppIntent 둘 다**: 혼란. 새로 = AppIntent. - **Spotlight 인덱스 한 번만**: stale. 변경 시 update. - **EntityQuery suggestedEntities 없음**: Shortcut UI 가 아무 거 없음. ## 🤖 LLM 활용 힌트 - AppEntity + AppIntent + AppShortcutsProvider 3종. - Widget interactivity 도 같은 intent. - iOS 18 Apple Intelligence 자동 활용. ## 🔗 관련 문서 - [[iOS_Widget_Extension]] - [[iOS_Universal_Links_Deep_Linking]] - [[iOS_Live_Activities]]