App Intents in iOS 26: Complete Gids voor Interactive Widgets, Siri en Apple Intelligence

App Intents in iOS 26 vervangen SiriKit en zijn de enige route naar interactieve widgets, Control Center en Apple Intelligence. Complete gids met code.

App Intents iOS 26 Gids: Widgets & Siri

Bijgewerkt: 4 september 2026

App Intents in iOS 26 zijn een Swift-framework waarmee je app-functionaliteit blootstelt aan het systeem, zodat gebruikers acties kunnen uitvoeren via Siri, Shortcuts, Spotlight, interactieve widgets, Control Center en Apple Intelligence, zonder dat ze je app hoeven te openen. In vergelijking met SiriKit is App Intents pure Swift, deelbaar tussen iOS, iPadOS, macOS, visionOS en watchOS, en sinds iOS 26 diep geïntegreerd met de on-device modellen van Apple Intelligence. Eerlijk gezegd: als je nog met Intent Definition-bestanden werkt, ga je in deze gids het beste opluchtingsgevoel van je jaar krijgen. We bouwen hier stap voor stap een productiewaardig intent-systeem op.

  • App Intents vervangen SiriKit voor nieuwe integraties en zijn de enige route naar interactieve widgets, Control Center-controls en Apple Intelligence-acties.
  • Een AppIntent heeft een title, optionele @Parameter-eigenschappen en een perform()-methode die op de MainActor draait, tenzij je expliciet nonisolated markeert.
  • Interactieve widgets in iOS 26 gebruiken Button(intent:) en Toggle(intent:). De widget wordt binnen ~200 ms herladen na een succesvolle uitvoering.
  • AppEntity en EntityQuery maken je data doorzoekbaar in Spotlight en beschikbaar als parameter-opties in Shortcuts en Siri.
  • Apple Intelligence gebruikt je geregistreerde AppShortcut-set als semantische index. Goede synoniemen bepalen of Siri je intent kiest.
  • Dezelfde intent draait op iPhone, iPad, Mac Catalyst, visionOS en watchOS 12, met platform-specifieke UI-verschillen die je moet plannen.

Wat zijn App Intents in iOS 26?

Het App Intents-framework is Apples declaratieve API waarmee acties, entiteiten en zoekresultaten uit je app worden aangeboden aan het systeem. Waar SiriKit in 2016 draaide om vaste "intent domains" (bellen, betalen, workouts), is App Intents domein-agnostisch. Elke publieke actie in je app kan een AppIntent zijn. In iOS 26 heeft Apple het framework op drie manieren uitgebreid: @AssistantIntent voor Apple Intelligence, ControlWidget voor Control Center, en async-parameter-resolution die native met Swift 6.2-concurrency samenwerkt.

Wat maakt dit belangrijk voor pragmatische engineers? Elke iOS-oppervlakte die extern een actie in je app kan starten (Siri, Shortcuts.app, Spotlight, de widget-galerij, het slotscherm, de Dynamic Island, Control Center, en sinds iOS 26 ook de Apple Intelligence-samenvattingen) vraagt exact dezelfde AppIntent-definitie op. Eén type, één perform()-implementatie, zes tot acht uitvoeringsplekken. Als je nog INIntent-subclasses of Intent Definition-bestanden onderhoudt, is 2026 het jaar om te migreren: SiriKit ontvangt geen nieuwe capaciteiten meer buiten de originele domeinen.

De basisstructuur van een AppIntent

Een minimale intent bestaat uit vier elementen: een struct die AppIntent conformt, een title (LocalizedStringResource), eventuele @Parameter-eigenschappen en een perform()-methode. Onder de motorkap serialiseert het systeem je struct via Codable. Dat is meteen de reden waarom je alleen Codable-compatibele waardetypes als parameter mag gebruiken.

import AppIntents
import SwiftUI

struct MarkTaskDoneIntent: AppIntent {
    static var title: LocalizedStringResource = "Taak afvinken"
    static var description = IntentDescription(
        "Markeert een taak als voltooid en werkt de widget bij."
    )

    // Parameters zijn Codable-waarden of AppEntity-referenties.
    @Parameter(title: "Taak")
    var task: TaskEntity

    // openAppWhenRun = false laat de intent volledig op de achtergrond draaien.
    static var openAppWhenRun: Bool = false

    @MainActor
    func perform() async throws -> some IntentResult {
        try await TaskStore.shared.complete(id: task.id)
        return .result()
    }
}

De perform()-methode draait standaard op de MainActor. In iOS 26 kun je met nonisolated func perform() expliciet naar een achtergrond-executor uitwijken. Dat is handig voor CPU-intensieve intents die geen UI aanraken. Wil je een resultaat teruggeven aan Siri of Shortcuts? Wissel .result() voor .result(value: mijnWaarde) of .result(dialog: "Klaar!"). Voor gestructureerde spraakuitvoer (bijvoorbeeld "Ik heb 3 taken afgevinkt") gebruik je IntentDialog met een LocalizedStringResource zodat je vertaalbaar blijft.

Interactieve widgets bouwen met App Intents

Interactieve widgets kwamen in iOS 17, maar iOS 26 heeft de belangrijkste rauwe randen weggehaald. De widget wordt nu binnen ~200 ms herladen na een succesvolle perform(), timeline-invalidatie is impliciet, en Toggle(isOn:intent:) ondersteunt optimistische UI zonder handmatig snapshot-mocking. Alleen Button en Toggle mogen een intent starten binnen een widget. Geen TapGesture, geen NavigationLink.

import WidgetKit
import SwiftUI
import AppIntents

struct TaskListWidget: Widget {
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: "TaskList", provider: Provider()) { entry in
            TaskListView(entry: entry)
                .containerBackground(.regularMaterial, for: .widget)
        }
        .configurationDisplayName("Mijn taken")
        .supportedFamilies([.systemMedium, .accessoryRectangular])
    }
}

struct TaskListView: View {
    let entry: TaskEntry

    var body: some View {
        VStack(alignment: .leading, spacing: 6) {
            ForEach(entry.tasks) { task in
                Toggle(isOn: task.isDone, intent: MarkTaskDoneIntent(task: task)) {
                    Text(task.title).font(.callout)
                }
                .toggleStyle(.checklist) // Nieuw in iOS 26
            }
        }
        .padding()
    }
}

De .checklist toggle-stijl is nieuw in iOS 26 en rendert automatisch met Liquid Glass-materialen zodat je widget past bij de rest van het systeem. Voor slotscherm-widgets (.accessoryRectangular) valt de stijl automatisch terug op monochroom, dus test beide varianten in de widget-simulator.

App Entities, Queries en dynamische parameters

Een AppEntity is de App Intents-versie van een "domain model": een Codable representatie van iets in je app dat het systeem kan onthouden, tonen en doorgeven. Denk aan een taak, een noot, een auto, een boekhoofdstuk. Elke entity heeft een id, een displayRepresentation, en een gekoppelde EntityQuery die opzoek-, suggestie- en zoekopdrachten afhandelt.

struct TaskEntity: AppEntity, Identifiable {
    let id: UUID
    let title: String
    var isDone: Bool

    static var typeDisplayRepresentation: TypeDisplayRepresentation =
        "Taak"

    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(
            title: "\(title)",
            subtitle: isDone ? "Voltooid" : "Openstaand",
            image: .init(systemName: isDone ? "checkmark.circle.fill" : "circle")
        )
    }

    static var defaultQuery = TaskQuery()
}

struct TaskQuery: EntityQuery {
    func entities(for ids: [UUID]) async throws -> [TaskEntity] {
        try await TaskStore.shared.tasks(ids: ids)
    }

    func suggestedEntities() async throws -> [TaskEntity] {
        try await TaskStore.shared.recent(limit: 10)
    }

    // Vanaf iOS 26: async, met Spotlight-ondersteuning uit de doos.
    func entities(matching string: String) async throws -> [TaskEntity] {
        try await TaskStore.shared.search(query: string)
    }
}

Wanneer je entities(matching:) implementeert, verschijnen je taken automatisch in Spotlight-zoekresultaten en in de Apple Intelligence-samenvattingen op het slotscherm. Belangrijk: houd de query snel (< 100 ms), want het systeem timet uit en toont anders geen resultaten. Voor grote datasets gebruik je Core Data of SwiftData met een geïndexeerde string-property.

AppShortcuts, Siri en Spotlight-integratie

Een AppShortcut is de brug tussen je AppIntent en de gebruiker. Het definieert de spraakzinnen die Siri herkent, de titel in de Shortcuts.app, en de systeem-image. Alle shortcuts worden geregistreerd via een AppShortcutsProvider die het framework bij app-launch inleest.

struct MyAppShortcuts: AppShortcutsProvider {
    static var shortcutTileColor: ShortcutTileColor = .grayGreen

    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: MarkTaskDoneIntent(),
            phrases: [
                "Vink \(.applicationName) taak af",
                "Rond taak af in \(.applicationName)",
                "Markeer taak als voltooid in \(.applicationName)"
            ],
            shortTitle: "Taak afvinken",
            systemImageName: "checkmark.circle"
        )
        AppShortcut(
            intent: CreateTaskIntent(),
            phrases: [
                "Nieuwe taak in \(.applicationName)",
                "Voeg taak toe aan \(.applicationName)"
            ],
            shortTitle: "Nieuwe taak",
            systemImageName: "plus.circle"
        )
    }
}

Elke zin moet de \(.applicationName)-token bevatten. Dit is een harde vereiste van het framework, geen suggestie. In de praktijk betekent het dat gebruikers "Hé Siri, vink Reminders taak af" zeggen. Maak je zinnen zo natuurlijk mogelijk en varieer ze. Apple Intelligence gebruikt deze verzameling als semantische fingerprint om te bepalen of jouw intent past bij een gebruikersverzoek dat niet exact overeenkomt met de letterlijke zin.

Control Center-widgets en Focus-filters

Sinds iOS 18 kun je Control Center-controls uitbreiden met je eigen widgets; iOS 26 voegt ControlWidgetToggle met asynchrone value-providers toe. Een Control Center-widget is bijna identiek aan een reguliere widget, maar dan zonder TimelineProvider. Hij wordt lazy geëvalueerd bij het openen van Control Center.

struct FocusToggleControl: ControlWidget {
    var body: some ControlWidgetConfiguration {
        StaticControlConfiguration(kind: "focusToggle") {
            ControlWidgetToggle(
                "Deep Work",
                isOn: FocusState.isActive,
                action: ToggleFocusIntent()
            ) { isOn in
                Label(isOn ? "Actief" : "Uit", systemImage: "brain.head.profile")
            }
        }
        .displayName("Deep Work modus")
    }
}

Focus-filters volgen hetzelfde patroon: implementeer SetFocusFilterIntent zodat gebruikers per Focus-modus (Werk, Slaap, Persoonlijk) verschillende accounts, kanalen of instellingen kunnen kiezen die jouw app dan respecteert. Een e-mailclient toont bijvoorbeeld alleen het werkaccount tijdens de Werk-Focus. Deze filters draaien op alle Apple-platforms behalve tvOS en zijn een onderschatte manier om je app diep in het besturingssysteem te integreren.

App Intents en Apple Intelligence

Dit is de grote iOS 26-uitbreiding. Apple Intelligence gebruikt je geregistreerde AppShortcuts als index om te bepalen welke intents relevant zijn voor een gebruikersverzoek, zelfs als de zin niet letterlijk overeenkomt. Voor deep-integratie markeer je een intent met het @AssistantIntent-attribuut en kies je een schema uit de door Apple gedefinieerde categorieën (mail, journalen, notities, workouts, foto-editing, en meer).

@AssistantIntent(schema: .journal.createEntry)
struct CreateJournalEntryIntent: AppIntent {
    static var title: LocalizedStringResource = "Journal-notitie maken"

    @Parameter(title: "Inhoud")
    var content: String

    @Parameter(title: "Stemming")
    var mood: JournalMood?

    @MainActor
    func perform() async throws -> some IntentResult {
        try await JournalStore.shared.append(
            .init(content: content, mood: mood, date: .now)
        )
        return .result()
    }
}

Door het schema te kiezen krijg je twee voordelen. Apple Intelligence kan je intent koppelen aan systeem-brede acties (bijvoorbeeld "Voeg dit toe aan mijn dagboek" vanuit een foto-samenvatting), en het model weet welke parameters het moet extraheren uit natuurlijke taal. Voor on-device redenering rondom entities kun je combineren met het Foundation Models Framework. Denk aan het automatisch afleiden van een mood-classificatie uit de tekstinhoud voordat je de intent uitvoert.

Cross-platform: iPad, Mac, visionOS en watchOS

Dezelfde intent-code compileert voor iPhone, iPad, Mac (native en Catalyst), visionOS 3 en watchOS 12. Wat verschilt, is de oppervlakte waarop hij verschijnt. In mijn ervaring krijgen engineers hier de meeste verrassingen, dus een concreet overzicht.

OppervlakteiPhone/iPadmacOSvisionOSwatchOS
Interactieve widgetsJa (iOS 17+)Ja (Sonoma+)Ja (visionOS 2+)Ja (watchOS 11+)
SiriJaJaJaJa
Shortcuts.appJaJaJaNee
SpotlightJaJaNeeNee
Control Center-controlsJa (iOS 18+)NeeNeeNee
Apple IntelligenceJa (compatibel apparaat)Ja (M1+)JaBeperkt
Focus-filtersJaJaJaJa

Twee cross-platform valkuilen om te noteren. Ten eerste: op watchOS is er geen Shortcuts.app, dus verwacht niet dat een gebruiker daar handmatig een shortcut aanmaakt. Je moet vertrouwen op AppShortcutsProvider-registratie. Ten tweede: op visionOS hebben widgets geen "medium" of "large" familie zoals op iOS; ze zijn 3D-volumes met andere afmetingen. Gebruik #if os(visionOS) om je layout aan te passen. De intent-logica zelf hoeft niet te weten op welk platform ze draait, wat een enorm voordeel is ten opzichte van het oude SiriKit-model.

Debugging en veelvoorkomende valkuilen

App Intents debuggen is berucht lastig, omdat veel van de uitvoering buiten je proces plaatsvindt (widget-extensie, Siri-daemon, ControlCenterUIService). Xcode 26 heeft dit aanzienlijk verbeterd met de nieuwe "App Intents"-organizer onder Debug → App Intents, die realtime laat zien welke intents het systeem detecteert, welke schema's ze gebruiken en of Apple Intelligence ze indexeert.

De vijf meest voorkomende problemen die ik in code reviews tegenkom:

  1. Intent verschijnt niet in Shortcuts.app. Meestal ontbreekt AppShortcutsProvider-registratie, of gebruikt een phrase geen \(.applicationName)-token. Los op met xcrun appintentsnltester in Terminal.
  2. Widget refresht niet na intent. Vergeten om WidgetCenter.shared.reloadTimelines(ofKind:) aan te roepen als je een niet-Toggle intent gebruikt. Toggle en Button triggeren automatische reload; custom flows niet.
  3. Parameter-picker toont geen opties. Je EntityQuery.suggestedEntities() gooit een fout of retourneert een lege array. Test de query in isolatie met een unit test, want de fout wordt in productie stil geslikt.
  4. Siri herkent de zin niet. Apple Intelligence-indexering gebeurt asynchroon; na installatie kan het tot 30 minuten duren. Forceer met de Simulator via Settings → Developer → Reset AppIntents Metadata.
  5. Crash bij perform(). Vaak MainActor-schending. Als je nonisolated func perform() gebruikt en dan UI-code aanroept, crasht Swift 6.2's strikte concurrency-checker. Zie onze gids over type-veilige foutafhandeling in Swift 6.2 voor patronen die hier helpen.

Veelgestelde vragen

Wat is het verschil tussen App Intents en SiriKit?

SiriKit gebruikt vaste "intent domains" (bellen, betalen, workouts) en Intent Definition-bestanden; App Intents is puur Swift, domein-agnostisch en werkt op alle Apple-platforms plus Apple Intelligence. Voor nieuwe apps in 2026 kies je altijd App Intents, want SiriKit ontvangt geen nieuwe capaciteiten meer.

Kan een AppIntent op de achtergrond draaien zonder de app te openen?

Ja. Zet static var openAppWhenRun: Bool = false op je intent-struct. De perform()-methode wordt dan uitgevoerd in een korte achtergrond-executie (~10 seconden op iOS) zonder je app naar de voorgrond te brengen. Dit is de standaardconfiguratie voor widget-buttons en Control Center-toggles.

Werken App Intents op watchOS?

Ja, sinds watchOS 11 volledig ondersteund, inclusief interactieve complications. De Shortcuts.app ontbreekt op watchOS, dus alleen intents die je registreert via AppShortcutsProvider zijn beschikbaar via Siri en de widget-galerij. Focus-filters werken ook op watchOS 12.

Hoe integreer je App Intents met Apple Intelligence?

Markeer je intent met @AssistantIntent(schema: .category.action) en kies een schema uit de door Apple gedefinieerde lijst (journal, mail, photos, workouts, en meer). Apple Intelligence indexeert je AppShortcut-zinnen als semantische fingerprint en kan zo natuurlijke gebruikersverzoeken naar jouw intent routeren, zelfs als de exacte woorden verschillen.

Waarom verschijnt mijn intent niet in de Shortcuts-app?

Drie oorzaken in volgorde van waarschijnlijkheid: (1) je hebt geen AppShortcutsProvider-type geregistreerd, (2) een van je phrases mist de verplichte \(.applicationName)-token, of (3) de app is nog nooit vanuit de UI geopend na installatie. Reset de index met xcrun appintentsnltester reset en herstart de app.

Hiroshi Sato
Over de Auteur Hiroshi Sato

Apple Platforms specialist building for iOS, macOS, visionOS, and the occasional watchOS app nobody asked for.