App Intents 2.0 i Siri Shortcuts: przewodnik automatyzacji iOS 27
Kompletny przewodnik po App Intents 2.0 i Siri Shortcuts dla iOS 27. Tworzenie streaming responses, rozmów wieloturowych, View Annotations i integracja z Foundation Models.

App Intents 2.0 i Siri Shortcuts stanowią jedyną ścieżkę integracji aplikacji zewnętrznych z Siri w iOS 27. Po WWDC 2026 Apple wycofało SiriKit i pozycjonowało App Intents jako obowiązkowy framework do interakcji głosowych, wykrywania w Spotlight oraz automatyzacji.
Ten artykuł przedstawia kompletne tworzenie App Intents i Siri Shortcuts dla iOS 27, od fundamentalnych koncepcji po streaming responses, rozmowy wieloturowe i View Annotations API.
Zrozumienie frameworku App Intents 2.0
Framework App Intents, wprowadzony w iOS 16 i rozszerzony do wersji 2.0 na WWDC 2026, jest natywnym dla Swift, deklaratywnym frameworkiem do budowania akcji wykrywalnych przez system. iOS 27 wprowadza cztery główne nowości: streaming responses dla długotrwałych operacji, wieloturowe follow-upy konwersacyjne, View Annotations do referencji elementów ekranowych oraz App Schemas dla semantycznego rozumienia bez fraz treningowych.
Na WWDC 2026 Apple formalnie wycofało SiriKit i uczyniło App Intents jedynym sposobem interakcji Siri z aplikacjami zewnętrznymi. Istniejący kod SiriKit nadal kompiluje się z ostrzeżeniami o deprecjacji, ale Apple sygnalizuje dwu- do trzyletnią ramę wsparcia przed całkowitym usunięciem.
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))
}
}Intent deklaruje parametry przez property wrapper @Parameter, pozwalając Siri pytać o brakujące wartości w formie konwersacji. Metoda perform() wykonuje logikę biznesową i zwraca typizowany wynik. Sam system typów służy jako schema, którą Siri AI dynamicznie wykrywa.
Streaming Responses dla długotrwałych akcji
App Intents 2.0 wprowadza streaming responses, pozwalające intentom raportować postęp podczas wykonania zamiast blokować do zakończenia. Ta funkcjonalność adresuje scenariusze jak upload plików, synchronizacja danych czy złożone obliczenia wymagające feedbacku dla użytkownika.
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 umożliwiają naturalny feedback podczas operacji trwających dłużej niż kilka sekund, utrzymując zaangażowanie użytkownika zamiast pozostawiać go w ciszy.
Wieloturowe follow-upy konwersacyjne
Rozmowy wieloturowe pozwalają Siri zadawać pytania wyjaśniające i kontynuować interakcję w ramach jednej sesji. Ta funkcja przekształca App Intents z poleceń jednorazowych w konwersacyjne przepływy pracy.
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."
)
}
}Metoda requestValue(for:dialog:) wstrzymuje wykonanie do momentu otrzymania odpowiedzi użytkownika od Siri, tworząc naturalną wymianę zamiast wymagania wszystkich parametrów z góry.
View Annotations API dla referencji ekranowych
View Annotations API, nowość w iOS 27, pozwala użytkownikom odnosić się do elementów UI bezpośrednio w poleceniach Siri używając fraz jak "to zdjęcie", "trzecie" czy "ta wiadomość". Ta funkcjonalność wymaga adnotacji widoków SwiftUI informacjami semantycznymi.
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.")
}
}Kiedy użytkownik mówi "udostępnij to zdjęcie" podczas przeglądania siatki, Siri rozwiązuje "to" na aktualnie sfokusowany lub ostatnio tapnięty PhotoEntity poprzez adnotację. To eliminuje konieczność słownego opisywania elementów.
View Annotations wymagają iOS 27, ale sama warstwa App Intents działa na każdym urządzeniu z iOS 27, włączając iPhone 11 i nowsze. Funkcje Apple Intelligence jak świadomość ekranu wymagają iPhone 15 Pro lub nowszego.
Definiowanie App Entities dla danych
App Entities reprezentują "rzeczowniki" aplikacji: obiekty, na których operują intenty. Pozwalają Siri rozumieć, wyszukiwać i manipulować danymi aplikacji. Tworzenie efektywnych encji jest kluczowe dla wzorców zarządzania stanem SwiftUI w aplikacjach opartych na intentach.
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) }
}
}Protokół EntityStringQuery dodaje funkcjonalność wyszukiwania tekstowego, pozwalając Siri znajdować encje po nazwie. Metoda suggestedEntities() zasila interfejsy Siri i Skrótów odpowiednimi opcjami.
Należy używać AppEnum dla typów ze stałym zbiorem wartości (priorytet, status), a AppEntity dla dynamicznych typów tworzonych przez użytkownika (zadania, notatki, kontakty). Mieszanie ich powoduje niepotrzebną złożoność.
Tworzenie App Enums dla stałych wartości
App Enums udostępniają systemowi typy wyliczeniowe, pozwalając Siri oferować kontekstowe wybory z wizualnymi reprezentacjami.
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")
)
]
}Ikony SF Symbols wzbogacają wyświetlanie w Skrótach i sugestiach Siri, przyspieszając wybór względem opisu słownego.
Gotowy na rozmowy o iOS?
Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.
Implementacja AppShortcutsProvider
AppShortcutsProvider udostępnia App Shortcuts systemowi, czyniąc je natychmiast dostępnymi bez konfiguracji użytkownika. Te skróty pojawiają się w Spotlight, Siri, na Action Button oraz w nowych agentowych przepływach Siri AI.
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"
)
}
}Frazy głosowe muszą zawierać placeholder (.applicationName), aby Siri zidentyfikowała aplikację docelową. Dynamiczne parametry jak (.) umożliwiają komendy kontekstowe.
Intenty w interaktywnych widgetach
App Intents integrują się z WidgetKit do tworzenia interaktywnych widgetów. Zrozumienie wzorców nawigacji SwiftUI pomaga przy budowaniu przejść widget-aplikacja.
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)
}
}Widgety używają składni Button(intent:) aby połączyć interakcję bezpośrednio z App Intent bez otwierania aplikacji.
Integracja z Foundation Models Framework
iOS 27 wprowadza Foundation Models framework, umożliwiający wnioskowanie LLM na urządzeniu. Choć Foundation Models nie ma bezpośredniej integracji z Siri, aplikacje mogą go używać wewnątrz App Intents do przetwarzania języka naturalnego lub generowania odpowiedzi.
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 działa z prędkością około 30 tokenów na sekundę na urządzeniu bez żadnych kosztów per zapytanie. Framework wymaga iPhone 15 Pro lub iPhone 16 i nowszych do przetwarzania na urządzeniu.
Migracja z SiriKit do App Intents
Dla aplikacji wciąż używających SiriKit, migracja przebiega według ustalonego procesu. Xcode 27 oferuje narzędzie "Convert to App Intent" dla konfiguracji widgetów, ale niestandardowe handlery wymagają ręcznego przepisania.
// 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))
}
}Migracja eliminuje pliki .intentdefinition i targety Intent Extension. Cała logika intentów przenosi się do głównego targetu aplikacji jako struktury Swift.
Testowanie App Intents
Framework AppIntentsTesting waliduje intenty przez rzeczywistą infrastrukturę Siri, Skrótów i Spotlight bez mocków.
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)
}
}Testy weryfikują zachowanie intentów niezależnie od interfejsu systemu, wyłapując regresje przed wdrożeniem.
Źródła
- Apple WWDC 2026 Announcements : App Intents 2.0 i deprecjacja SiriKit
- Swift.org Blog : wydania Swift 6.3 i 6.4
- Apple Developer News : wymagania iOS 27 SDK i Foundation Models framework
- iOS 27 App Intents Developer Guide : szczegóły streaming responses i View Annotations
Lista kontrolna implementacji App Intents iOS 27
Dla aplikacji celujących w iOS 27, App Intents nie są już opcjonalne. Siri AI komponuje wielokrokowe akcje między aplikacjami, a aplikacje bez publikowanych intentów są wykluczone z tych agentowych przepływów.
- Utwórz AppIntents dla głównych akcji aplikacji
- Zdefiniuj AppEntities dla manipulowalnych danych
- Użyj AppEnum dla typów wyliczeniowych
- Zaimplementuj AppShortcutsProvider z frazami głosowymi
- Przestrzegaj limitu maksymalnie 10 App Shortcuts
- Uwzględnij
(.applicationName)we wszystkich frazach - Dodaj View Annotations do widoków SwiftUI dla referencji ekranowych
- Zaimplementuj streaming responses dla długotrwałych operacji
- Wspieraj rozmowy wieloturowe dla złożonych przepływów
- Zmigruj z SiriKit przed zamknięciem okna wsparcia
- Testuj intenty z frameworkiem AppIntentsTesting
- Zlokalizuj tytuły i opisy
Zacznij ćwiczyć!
Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.
Znajdziesz błąd w iOS?
Prawdziwy fragment kodu, ukryty błąd, jedna próba dziennie. Bez konta, żeby spróbować.

Autor:
Anthony Fillion-MailletZałożyciel SharpSkill
Programista fullstack od ponad 10 lat. Prowadzi SharpSkill i odpowiada za wszystko, co się tu ukazuje.
Zaktualizowano 20 sierpnia 2026
Tagi
Udostępnij
Powiązane artykuły

WidgetKit iOS 17-26: Interaktywne Widgety z App Intents
Kompletny przewodnik tworzenia interaktywnych widgetów iOS z WidgetKit i App Intents. Obejmuje przyciski, przełączniki, animacje, materiał Liquid Glass iOS 26 i aktualizacje WWDC 2026.

Combine vs async/await w Swift: Wzorce Progresywnej Migracji
Kompletny przewodnik po migracji z Combine do async/await w Swift: progresywne strategie, wzorce mostkowania i współistnienie paradygmatów w bazach kodu iOS.

Pytania rekrutacyjne o dostępność iOS w 2026: VoiceOver i Dynamic Type
Przygotuj się do rozmów iOS z kluczowymi pytaniami o dostępność: VoiceOver, Dynamic Type, semantyczne traits i audyty.