🌐 KO

πŸ—£οΈ Siri μŒμ„± μ œμ–΄ μ•± λ§Œλ“€κΈ°

⭐ Difficulty: ⭐⭐⭐ ⏱️ Est. Time: 2-3h πŸ“‚ App Frameworks

Build an app that works when you say "Add a todo" using App Intents.

✨ App Intents?

App Intents exposes your app's features to Siri, Shortcuts, and Spotlight. Available on iOS 16+ and much simpler than the previous SiriKit.

πŸ“ 첫 번째 Intent λ§Œλ“€κΈ°

AddTodoIntent.swift
import AppIntents

struct AddTodoIntent: AppIntent {
    static var title: LocalizedStringResource = "ν•  일 μΆ”κ°€"
    
    @Parameter(title: "제λͺ©")
    var todoTitle: String
    
    func perform() async throws -> some IntentResult {
        TodoStore.shared.add(title: todoTitle)
        return .result(dialog: "\(todoTitle) μΆ”κ°€ μ™„λ£Œ!")
    }
}

🎀 Siri μŒμ„± λͺ…λ Ή 등둝

Shortcuts.swift
struct TodoShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: AddTodoIntent(),
            phrases: [
                "ν•  일 μΆ”κ°€ν•΄μ€˜ \(.applicationName)",
                "\(.applicationName)에 ν•  일 μΆ”κ°€"
            ],
            shortTitle: "ν•  일 μΆ”κ°€",
            systemImageName: "plus.circle"
        )
    }
}

πŸ’‘ HIG 팁

Write phrases as natural sentences β€” use expressions people would actually say, like "Add a todo" or "Create a new task."

πŸ”„ νŒŒλΌλ―Έν„° λŒ€ν™” 흐름

νŒŒλΌλ―Έν„°κ°€ μ—†μœΌλ©΄ Siriκ°€ μžλ™μœΌλ‘œ λ¬Όμ–΄λ΄…λ‹ˆλ‹€:

Dialog.swift
guard let title = todoTitle else {
    throw $todoTitle.needsValueError("μ–΄λ–€ ν•  일을 μΆ”κ°€ν• κΉŒμš”?")
}

πŸ“‹ Entity μ •μ˜

Define todo items as Entities so Siri can suggest and search tasks:

TodoEntity.swift
struct TodoEntity: AppEntity {
    static var typeDisplayRepresentation: TypeDisplayRepresentation {
        "ν•  일"
    }

    var id: UUID
    var title: String
    var isCompleted: Bool

    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(title)")
    }

    // Spotlight 검색 지원
    static var defaultQuery = TodoEntityQuery()
}

πŸ” EntityQuery κ΅¬ν˜„

TodoEntityQuery.swift
struct TodoEntityQuery: EntityQuery {
    func entities(for identifiers: [UUID]) async throws -> [TodoEntity] {
        TodoStore.shared.todos.filter { identifiers.contains($0.id) }
    }

    func suggestedEntities() async throws -> [TodoEntity] {
        // λ―Έμ™„λ£Œ ν•­λͺ© 3개 μ œμ•ˆ
        TodoStore.shared.todos
            .filter { !$0.isCompleted }
            .prefix(3)
            .map(TodoEntity.init)
    }
}

πŸ“± SwiftUI Integration

Use AppIntentsUI to customize Siri responses with SwiftUI:

AddTodoIntent+UI.swift
import AppIntentsUI

extension AddTodoIntent {
    @MainActor
    func perform() async throws -> some IntentResult & ProvidesDialog & ShowsSnippetView {
        let todo = TodoStore.shared.add(title: todoTitle)

        return .result(
            dialog: "\(todoTitle) μΆ”κ°€ν–ˆμ–΄μš”!",
            view: TodoSnippetView(todo: todo)
        )
    }
}

struct TodoSnippetView: View {
    let todo: TodoEntity

    var body: some View {
        HStack {
            Image(systemName: "checkmark.circle")
            Text(todo.title)
        }
        .padding()
    }
}

πŸ’‘ Testing 방법

Run in Xcode and ask Siri "Add a todo [app name]." In the simulator, test via Hardware β†’ Siri.

πŸ“¦ Learning Resources

πŸ“š
DocC Tutorial
Try it in Xcode
πŸ’»
GitHub Project
Complete Source Code
🍎
Apple HIG Docs
App Intents κ°€μ΄λ“œ

πŸ“Ž Apple Official Resources

πŸ“˜ Documentation πŸ’» Sample Code 🎬 WWDC Sessions