App Intents 2.0 en Siri Shortcuts: iOS 27 automatiseringsgids

Volledige gids voor App Intents 2.0 en Siri Shortcuts voor iOS 27. Streaming-responses, multi-turn conversaties, View Annotations en Foundation Models integratie.

App Intents en Siri Shortcuts voor geavanceerde iOS-automatisering met Swift en Apple Intelligence

App Intents 2.0 en Siri Shortcuts vormen de enige weg voor third-party apps om te integreren met Siri op iOS 27. Na WWDC 2026 heeft Apple SiriKit afgeschaft en App Intents gepositioneerd als het verplichte framework voor spraakinteractie, Spotlight-ontdekking en automatiserings-workflows.

Wat dit artikel behandelt

Dit artikel presenteert de volledige creatie van App Intents en Siri Shortcuts voor iOS 27, van fundamentele concepten tot streaming-responses, multi-turn conversaties en de View Annotations API.

Het App Intents 2.0 framework begrijpen

Het App Intents framework, geïntroduceerd met iOS 16 en uitgebreid naar versie 2.0 op WWDC 2026, is een Swift-native, declaratief framework voor het bouwen van systeemontdekbare acties. iOS 27 brengt vier grote toevoegingen: streaming-responses voor langlopende operaties, multi-turn conversationele follow-ups, View Annotations voor het refereren naar schermelementen, en App Schemas voor semantisch begrip zonder trainingsfrases.

Op WWDC 2026 heeft Apple formeel SiriKit afgeschaft en App Intents de exclusieve manier gemaakt waarop Siri kan interageren met third-party apps. Bestaande SiriKit-code blijft compileren met deprecation-waarschuwingen, maar Apple heeft een ondersteuningsvenster van twee tot drie jaar aangegeven voor verwijdering.

TaskIntent.swiftswift
import AppIntents

// An AppIntent represents an action users can perform
struct CreateTaskIntent: AppIntent {
    // Title displayed in Shortcuts and Siri
    static var title: LocalizedStringResource = "Create a task"

    // Description for accessibility and suggestions
    static var description = IntentDescription(
        "Creates a new task in the application."
    )

    // Parameter with automatic validation
    @Parameter(title: "Task title")
    var taskTitle: String

    // Optional parameter with default value
    @Parameter(title: "Priority", default: .medium)
    var priority: TaskPriority

    // Action execution with async/await
    func perform() async throws -> some IntentResult & ReturnsValue<TaskEntity> {
        // Create task via service
        let task = TaskService.shared.createTask(
            title: taskTitle,
            priority: priority
        )

        // Return created entity for chaining
        return .result(value: TaskEntity(task: task))
    }
}

De intent declareert parameters met de @Parameter property wrapper, waardoor Siri ontbrekende waarden conversationeel kan opvragen. De perform() methode voert business logic uit en retourneert een getypeerd resultaat. Het type-systeem zelf dient als het schema dat Siri AI dynamisch ontdekt.

Streaming-responses voor langlopende acties

App Intents 2.0 introduceert streaming-responses, waardoor intents voortgang kunnen rapporteren tijdens uitvoering in plaats van te blokkeren tot voltooiing. Deze mogelijkheid adresseert scenario's zoals bestandsuploads, datasynchronisatie of complexe berekeningen waar gebruikers feedback nodig hebben.

StreamingExportIntent.swiftswift
import AppIntents

struct ExportDataIntent: AppIntent {
    static var title: LocalizedStringResource = "Export data"

    @Parameter(title: "Format")
    var format: ExportFormat

    // Streaming response for progress reporting
    func perform() async throws -> some IntentResult & ProvidesDialog {
        let totalItems = DataService.shared.itemCount
        var processed = 0

        // Stream progress updates to Siri
        for item in DataService.shared.allItems {
            await exportItem(item, format: format)
            processed += 1

            // Report progress at intervals
            if processed % 100 == 0 {
                await reportProgress(
                    "Exported (processed) of (totalItems) items..."
                )
            }
        }

        return .result(
            dialog: "Export complete. (totalItems) items saved as (format.rawValue)."
        )
    }
}

Streaming-responses maken natuurlijke feedback mogelijk tijdens operaties die meer dan enkele seconden duren, waardoor de gebruiker betrokken blijft in plaats van in stilte te wachten.

Multi-turn conversaties

Multi-turn conversaties stellen Siri in staat verduidelijkende vragen te stellen en de interactie binnen een enkele sessie voort te zetten. Deze functie transformeert App Intents van eenmalige commando's naar conversationele workflows.

ConversationalTaskIntent.swiftswift
import AppIntents

struct SmartTaskIntent: AppIntent {
    static var title: LocalizedStringResource = "Create smart task"

    @Parameter(title: "Task title")
    var taskTitle: String?

    @Parameter(title: "Priority")
    var priority: TaskPriority?

    @Parameter(title: "Due date")
    var dueDate: Date?

    // Multi-turn conversation flow
    func perform() async throws -> some IntentResult & ProvidesDialog {
        // Request missing parameters conversationally
        let title = try await taskTitle ?? requestValue(
            for: .,
            dialog: "What should the task be called?"
        )

        let taskPriority = try await priority ?? requestValue(
            for: .,
            dialog: "What priority level?"
        )

        // Optional follow-up
        let date: Date?
        if try await requestConfirmation(
            result: .result(dialog: "Should this task have a due date?")
        ) {
            date = try await requestValue(
                for: .,
                dialog: "When is it due?"
            )
        } else {
            date = nil
        }

        let task = TaskService.shared.createTask(
            title: title,
            priority: taskPriority,
            dueDate: date
        )

        return .result(
            dialog: "Created '(task.title)' with (taskPriority.rawValue) priority."
        )
    }
}

De requestValue(for:dialog:) methode pauzeert de uitvoering totdat Siri de respons van de gebruiker ontvangt, wat een natuurlijke heen-en-weer uitwisseling creëert in plaats van alle parameters vooraf te vereisen.

View Annotations API voor schermreferenties

De View Annotations API, nieuw in iOS 27, stelt gebruikers in staat UI-elementen direct te refereren in Siri-commando's met frases zoals "deze foto", "de derde" of "dat bericht". Deze mogelijkheid vereist het annoteren van SwiftUI views met semantische informatie.

AnnotatedPhotoView.swiftswift
import SwiftUI
import AppIntents

struct PhotoGridView: View {
    let photos: [Photo]

    var body: some View {
        LazyVGrid(columns: [GridItem(.adaptive(minimum: 100))]) {
            ForEach(photos) { photo in
                PhotoThumbnail(photo: photo)
                    // Annotate view for Siri reference
                    .appIntentAnnotation(
                        entity: PhotoEntity(photo: photo),
                        label: photo.title
                    )
            }
        }
    }
}

// Intent that accepts view-referenced entities
struct SharePhotoIntent: AppIntent {
    static var title: LocalizedStringResource = "Share photo"

    // Parameter resolved from on-screen annotation
    @Parameter(title: "Photo", supportsViewAnnotation: true)
    var photo: PhotoEntity

    func perform() async throws -> some IntentResult & ProvidesDialog {
        await ShareService.share(photo.id)
        return .result(dialog: "Photo shared.")
    }
}

Wanneer een gebruiker "deel deze foto" zegt terwijl het grid wordt bekeken, lost Siri "deze" op naar de momenteel gefocuste of laatst getapte PhotoEntity via de annotatie. Dit elimineert de wrijving van het verbaal beschrijven van items.

Apparaatcompatibiliteit

View Annotations vereisen iOS 27, maar de App Intents-laag werkt op elk iOS 27-apparaat inclusief iPhone 11 en nieuwer. Apple Intelligence-functies zoals schermbewustzijn vereisen iPhone 15 Pro of later.

App Entities definiëren voor data

App Entities vertegenwoordigen de "zelfstandige naamwoorden" van de applicatie: objecten waarop intents opereren. Ze stellen Siri in staat app-data te begrijpen, te doorzoeken en te manipuleren. Effectieve entities bouwen is essentieel voor SwiftUI state management patronen in intent-gedreven apps.

TaskEntity.swiftswift
import AppIntents

// Internal data model
struct Task: Identifiable, Codable {
    let id: UUID
    var title: String
    var priority: TaskPriority
    var isCompleted: Bool
    var dueDate: Date?
}

// Entity exposed to the system
struct TaskEntity: AppEntity {
    // Required unique identifier
    var id: UUID

    // Displayable properties
    var title: String
    var priority: TaskPriority
    var isCompleted: Bool

    // Display configuration in the system
    static var typeDisplayRepresentation: TypeDisplayRepresentation = "Task"

    // Visual representation of the instance
    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(
            title: "(title)",
            subtitle: "(priority.rawValue)",
            image: .init(systemName: isCompleted ? "checkmark.circle.fill" : "circle")
        )
    }

    // Default query for searching entities
    static var defaultQuery = TaskEntityQuery()

    // Initializer from internal model
    init(task: Task) {
        self.id = task.id
        self.title = task.title
        self.priority = task.priority
        self.isCompleted = task.isCompleted
    }
}

// Optimized entity query with search
struct TaskEntityQuery: EntityStringQuery {
    // Text search with service-side filtering
    func entities(matching string: String) async throws -> [TaskEntity] {
        TaskService.shared.search(query: string, limit: 10)
            .map { TaskEntity(task: /bin/bash) }
    }

    // Search by identifiers
    func entities(for identifiers: [UUID]) async throws -> [TaskEntity] {
        TaskService.shared.fetchTasks()
            .filter { identifiers.contains(/bin/bash.id) }
            .map { TaskEntity(task: /bin/bash) }
    }

    // Limited suggestions for performance
    func suggestedEntities() async throws -> [TaskEntity] {
        TaskService.shared.fetchRecentTasks(limit: 5)
            .map { TaskEntity(task: /bin/bash) }
    }
}

Het EntityStringQuery protocol voegt tekstzoekmogelijkheid toe, waardoor Siri entities op naam kan vinden. De suggestedEntities() methode voedt Siri en Opdrachten-interfaces met relevante opties.

Gebruik AppEnum voor vaste waarden

Gebruik AppEnum voor types met een vaste set waarden (prioriteit, status), en AppEntity voor dynamische door gebruikers gecreëerde types (taken, notities, contacten). Ze mengen veroorzaakt onnodige complexiteit.

App Enums maken voor vaste waarden

App Enums stellen opgesomde types beschikbaar aan het systeem, waardoor Siri contextuele keuzes kan bieden met visuele representaties.

TaskPriority.swiftswift
import AppIntents

// Enum exposed to the system
enum TaskPriority: String, AppEnum, Codable {
    case low
    case medium
    case high

    // Type name displayed
    static var typeDisplayRepresentation: TypeDisplayRepresentation = "Priority"

    // Representation of each case
    static var caseDisplayRepresentations: [TaskPriority: DisplayRepresentation] = [
        .low: DisplayRepresentation(
            title: "Low",
            image: .init(systemName: "arrow.down.circle")
        ),
        .medium: DisplayRepresentation(
            title: "Medium",
            image: .init(systemName: "minus.circle")
        ),
        .high: DisplayRepresentation(
            title: "High",
            image: .init(systemName: "exclamationmark.circle")
        )
    ]
}

SF Symbols-iconen verrijken de weergave in Opdrachten en Siri-suggesties, waardoor selectie sneller is dan verbale beschrijvingen.

Klaar om je iOS gesprekken te halen?

Oefen met onze interactieve simulatoren, flashcards en technische tests.

AppShortcutsProvider implementeren

De AppShortcutsProvider stelt App Shortcuts beschikbaar aan het systeem, direct beschikbaar zonder gebruikersconfiguratie. Deze shortcuts verschijnen in Spotlight, Siri, de Action Button en de nieuwe agentische Siri AI-workflows.

ShortcutsProvider.swiftswift
import AppIntents

// Provider declaring all app shortcuts
struct TaskAppShortcutsProvider: AppShortcutsProvider {
    // Maximum 10 shortcuts per application
    @AppShortcutsBuilder
    static var appShortcuts: [AppShortcut] {
        // Shortcut to create a task
        AppShortcut(
            intent: CreateTaskIntent(),
            phrases: [
                // The .applicationName placeholder is REQUIRED
                "Create a task with (.applicationName)",
                "New task in (.applicationName)",
                "Add a task to (.applicationName)"
            ],
            shortTitle: "Create Task",
            systemImageName: "plus.circle"
        )

        // Shortcut with dynamic parameter
        AppShortcut(
            intent: CompleteTaskIntent(),
            phrases: [
                "Complete (.) in (.applicationName)",
                "Mark (.) as done with (.applicationName)"
            ],
            shortTitle: "Complete Task",
            systemImageName: "checkmark.circle"
        )

        // Shortcut for smart conversational intent
        AppShortcut(
            intent: SmartTaskIntent(),
            phrases: [
                "Quick task (.applicationName)",
                "Remind me (.applicationName)"
            ],
            shortTitle: "Smart Task",
            systemImageName: "brain"
        )
    }
}

Spraakfrases moeten de (.applicationName) placeholder bevatten zodat Siri de doelapp identificeert. Dynamische parameters zoals (.) maken contextuele commando's mogelijk.

Intents in interactieve widgets

App Intents integreren met WidgetKit om interactieve widgets te maken. Het begrijpen van SwiftUI navigatiepatronen helpt bij het bouwen van widget-naar-app transities.

TaskWidgetIntents.swiftswift
import AppIntents
import WidgetKit

// Widget-optimized intent (fast execution)
struct ToggleTaskFromWidgetIntent: AppIntent {
    static var title: LocalizedStringResource = "Toggle task"

    @Parameter(title: "Task ID")
    var taskID: String

    init() {}

    init(taskID: UUID) {
        self.taskID = taskID.uuidString
    }

    // No dialog for widgets
    func perform() async throws -> some IntentResult {
        guard let uuid = UUID(uuidString: taskID) else {
            return .result()
        }

        TaskService.shared.toggleCompletion(taskId: uuid)

        // Immediate widget refresh
        WidgetCenter.shared.reloadTimelines(ofKind: "TaskWidget")

        return .result()
    }
}

// Widget view with interactive button
import SwiftUI

struct TaskWidgetView: View {
    let task: Task

    var body: some View {
        Button(intent: ToggleTaskFromWidgetIntent(taskID: task.id)) {
            HStack {
                Image(systemName: task.isCompleted ? "checkmark.circle.fill" : "circle")
                    .foregroundStyle(task.isCompleted ? .green : .secondary)

                Text(task.title)
                    .strikethrough(task.isCompleted)
            }
            .padding()
        }
        .buttonStyle(.plain)
    }
}

Widgets gebruiken de Button(intent:) syntax om interactie direct te koppelen aan het App Intent zonder de applicatie te openen.

Foundation Models Framework integratie

iOS 27 introduceert het Foundation Models framework, dat on-device LLM-inferentie mogelijk maakt. Hoewel Foundation Models geen directe Siri-integratie heeft, kunnen apps het binnen App Intents gebruiken om natuurlijke taal te verwerken of responses te genereren.

AIAssistedIntent.swiftswift
import AppIntents
import FoundationModels

struct SummarizeNotesIntent: AppIntent {
    static var title: LocalizedStringResource = "Summarize notes"

    @Parameter(title: "Topic")
    var topic: String

    func perform() async throws -> some IntentResult & ProvidesDialog {
        let notes = NoteService.shared.fetchNotes(matching: topic)
        let content = notes.map(.content).joined(separator: "

")

        // Use Foundation Models for on-device summarization
        let model = LanguageModel.default
        let summary = try await model.generate(
            prompt: "Summarize these notes in 2 sentences: (content)",
            maxTokens: 100
        )

        return .result(dialog: IntentDialog(summary))
    }
}

Foundation Models draait op ongeveer 30 tokens per seconde on-device zonder kosten per verzoek. Het framework vereist iPhone 15 Pro of iPhone 16 en later voor on-device verwerking.

Migratie van SiriKit naar App Intents

Voor apps die nog SiriKit gebruiken, volgt de migratie een gestructureerd proces. Xcode 27 biedt een "Convert to App Intent" tool voor Widget-configuraties, maar aangepaste handlers vereisen handmatige herschrijving.

swift
// Before: SiriKit Intent Handler
class CreateTaskIntentHandler: NSObject, CreateTaskIntentHandling {
    func handle(intent: CreateTaskIntent) async -> CreateTaskIntentResponse {
        guard let title = intent.taskTitle else {
            return CreateTaskIntentResponse(code: .failure, userActivity: nil)
        }

        let task = TaskService.shared.createTask(title: title)
        return CreateTaskIntentResponse.success(task: task)
    }
}

// After: App Intent (iOS 27)
struct CreateTaskIntent: AppIntent {
    static var title: LocalizedStringResource = "Create a task"

    @Parameter(title: "Task title")
    var taskTitle: String

    func perform() async throws -> some IntentResult & ReturnsValue<TaskEntity> {
        let task = TaskService.shared.createTask(title: taskTitle)
        return .result(value: TaskEntity(task: task))
    }
}

De migratie elimineert .intentdefinition bestanden en Intent Extension targets. Alle intent-logica verhuist naar het hoofdapp-target als Swift structs.

App Intents testen

Het AppIntentsTesting framework valideert intents via de daadwerkelijke Siri, Opdrachten en Spotlight-infrastructuur zonder mocks.

TaskIntentTests.swiftswift
import XCTest
import AppIntentsTesting
@testable import TaskApp

final class TaskIntentTests: XCTestCase {

    override func setUp() {
        super.setUp()
        TaskService.shared.reset()
    }

    func testCreateTaskIntent() async throws {
        // Given
        var intent = CreateTaskIntent()
        intent.taskTitle = "Test Task"
        intent.priority = .high

        // When
        let result = try await intent.perform()

        // Then
        let tasks = TaskService.shared.fetchTasks()
        XCTAssertEqual(tasks.count, 1)
        XCTAssertEqual(tasks.first?.title, "Test Task")
        XCTAssertEqual(tasks.first?.priority, .high)
    }

    func testEntityQuery() async throws {
        // Given
        let task1 = TaskService.shared.createTask(title: "Task 1", priority: .low)
        let task2 = TaskService.shared.createTask(title: "Task 2", priority: .high)

        let query = TaskEntityQuery()

        // When
        let entities = try await query.entities(for: [task1.id, task2.id])

        // Then
        XCTAssertEqual(entities.count, 2)
    }

    func testStreamingIntent() async throws {
        // Given
        var intent = ExportDataIntent()
        intent.format = .json

        // When
        let result = try await intent.perform()

        // Then: verify completion dialog
        XCTAssertNotNil(result)
    }
}

Tests verifiëren intent-gedrag onafhankelijk van de systeeminterface, waardoor regressies worden gevonden voor deployment.

Sources

App Intents iOS 27 implementatie-checklist

Voor apps die iOS 27 targeten, zijn App Intents niet langer optioneel. Siri AI composeert multi-step acties over apps heen, en apps zonder gepubliceerde intents worden uitgesloten van deze agentische workflows.

  • AppIntents maken voor de hoofdacties van de app
  • AppEntities definiëren voor manipuleerbare data
  • AppEnum gebruiken voor opgesomde types
  • AppShortcutsProvider implementeren met spraakfrases
  • Het maximum van 10 App Shortcuts respecteren
  • (.applicationName) opnemen in alle frases
  • View Annotations toevoegen aan SwiftUI views voor schermreferenties
  • Streaming-responses implementeren voor langlopende operaties
  • Multi-turn conversaties ondersteunen voor complexe workflows
  • Migreren van SiriKit voordat het deprecation-venster sluit
  • Intents testen met het AppIntentsTesting framework
  • Titels en beschrijvingen lokaliseren

Begin met oefenen!

Test je kennis met onze gespreksimulatoren en technische tests.

Dagelijkse challenge

Zie jij de bug in iOS?

Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Anthony Fillion-Maillet

Geschreven door

Anthony Fillion-Maillet

Oprichter van SharpSkill

Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.

Bijgewerkt op 20 augustus 2026

Tags

#app-intents
#siri-shortcuts
#ios
#swift
#apple-intelligence

Delen

Gerelateerde artikelen