App Intents 2.0 và Siri Shortcuts: Hướng dẫn Tự động hóa iOS 27
Hướng dẫn đầy đủ về App Intents 2.0 và Siri Shortcuts cho iOS 27. Xây dựng streaming responses, hội thoại multi-turn, View Annotations và tích hợp với Foundation Models.

App Intents 2.0 và Siri Shortcuts là con đường duy nhất để ứng dụng bên thứ ba tích hợp với Siri trên iOS 27. Sau WWDC 2026, Apple đã ngừng hỗ trợ SiriKit và đặt App Intents là framework bắt buộc cho tương tác giọng nói, khám phá Spotlight và quy trình tự động hóa.
Bài viết trình bày toàn bộ quá trình tạo App Intents và Siri Shortcuts cho iOS 27, từ các khái niệm cơ bản cho đến streaming responses, hội thoại multi-turn và View Annotations API.
Tìm hiểu Framework App Intents 2.0
Framework App Intents, lần đầu được giới thiệu với iOS 16 và mở rộng lên phiên bản 2.0 tại WWDC 2026, là một framework Swift-native, khai báo để xây dựng các hành động mà hệ thống có thể khám phá. iOS 27 mang đến bốn cải tiến lớn: streaming responses cho các thao tác chạy lâu, follow-up hội thoại multi-turn, View Annotations để tham chiếu các phần tử trên màn hình, và App Schemas cho hiểu biết ngữ nghĩa mà không cần cụm từ huấn luyện.
Tại WWDC 2026, Apple chính thức ngừng hỗ trợ SiriKit và đặt App Intents là cách duy nhất Siri có thể tương tác với ứng dụng bên thứ ba. Mã SiriKit hiện tại vẫn biên dịch được với cảnh báo ngừng hỗ trợ, nhưng Apple đã báo hiệu khoảng thời gian hỗ trợ từ hai đến ba năm trước khi loại bỏ.
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 khai báo tham số bằng property wrapper @Parameter, cho phép Siri yêu cầu các giá trị thiếu theo cách hội thoại. Phương thức perform() thực thi logic nghiệp vụ và trả về kết quả đã định kiểu. Hệ thống kiểu chính nó đóng vai trò là schema mà Siri AI khám phá động.
Streaming Responses cho Thao tác Chạy Lâu
App Intents 2.0 giới thiệu streaming responses, cho phép intents báo cáo tiến trình trong quá trình thực thi thay vì chặn cho đến khi hoàn thành. Khả năng này xử lý các tình huống như tải file lên, đồng bộ dữ liệu, hoặc tính toán phức tạp khi người dùng cần phản hồi.
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 cho phép phản hồi tự nhiên trong các thao tác mất hơn vài giây, duy trì sự tương tác của người dùng thay vì để họ chờ đợi trong im lặng.
Hội thoại Multi-Turn với Follow-Ups
Hội thoại multi-turn cho phép Siri đặt câu hỏi làm rõ và tiếp tục tương tác trong một phiên. Tính năng này biến App Intents từ lệnh một lần thành quy trình hội thoại.
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: .$taskTitle,
dialog: "What should the task be called?"
)
let taskPriority = try await priority ?? requestValue(
for: .$priority,
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: .$dueDate,
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."
)
}
}Phương thức requestValue(for:dialog:) tạm dừng thực thi cho đến khi Siri nhận được phản hồi của người dùng, tạo ra sự trao đổi qua lại tự nhiên thay vì yêu cầu tất cả tham số ngay từ đầu.
View Annotations API cho Tham chiếu Trên Màn hình
View Annotations API, mới trong iOS 27, cho phép người dùng tham chiếu các phần tử UI trực tiếp trong lệnh Siri bằng các cụm từ như "ảnh này", "cái thứ ba", hoặc "tin nhắn đó". Khả năng này yêu cầu chú thích các view SwiftUI với thông tin ngữ nghĩa.
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.")
}
}Khi người dùng nói "chia sẻ ảnh này" trong khi xem lưới, Siri giải quyết "này" thành PhotoEntity đang được focus hoặc được chạm gần nhất thông qua chú thích. Điều này loại bỏ rào cản mô tả các mục bằng lời.
View Annotations yêu cầu iOS 27, nhưng layer App Intents hoạt động trên mọi thiết bị iOS 27 bao gồm iPhone 11 trở lên. Các tính năng Apple Intelligence như nhận biết trên màn hình cần iPhone 15 Pro trở lên.
Định nghĩa App Entities cho Dữ liệu
App Entities đại diện cho "danh từ" của ứng dụng: các đối tượng mà intents thao tác. Chúng cho phép Siri hiểu, tìm kiếm và xử lý dữ liệu ứng dụng. Xây dựng entities hiệu quả là thiết yếu cho các mẫu quản lý state SwiftUI trong ứng dụng điều khiển bằng intent.
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: $0) }
}
// Search by identifiers
func entities(for identifiers: [UUID]) async throws -> [TaskEntity] {
TaskService.shared.fetchTasks()
.filter { identifiers.contains($0.id) }
.map { TaskEntity(task: $0) }
}
// Limited suggestions for performance
func suggestedEntities() async throws -> [TaskEntity] {
TaskService.shared.fetchRecentTasks(limit: 5)
.map { TaskEntity(task: $0) }
}
}Giao thức EntityStringQuery thêm khả năng tìm kiếm văn bản, cho phép Siri tìm entities theo tên. Phương thức suggestedEntities() cung cấp cho giao diện Siri và Shortcuts các tùy chọn liên quan.
Sử dụng AppEnum cho các kiểu có tập giá trị cố định (mức độ ưu tiên, trạng thái), và AppEntity cho các kiểu động do người dùng tạo (nhiệm vụ, ghi chú, danh bạ). Trộn lẫn chúng gây ra sự phức tạp không cần thiết.
Tạo App Enums cho Giá trị Cố định
App Enums phơi bày các kiểu liệt kê cho hệ thống, cho phép Siri đưa ra các lựa chọn theo ngữ cảnh với biểu diễn trực quan.
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")
)
]
}Icon SF Symbols làm phong phú hiển thị trong Shortcuts và gợi ý Siri, giúp lựa chọn nhanh hơn mô tả bằng lời.
Sẵn sàng chinh phục phỏng vấn iOS?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Triển khai AppShortcutsProvider
AppShortcutsProvider phơi bày App Shortcuts cho hệ thống, làm chúng có sẵn ngay lập tức mà không cần cấu hình người dùng. Các phím tắt này xuất hiện trong Spotlight, Siri, Action Button và các quy trình agentic Siri AI mới.
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 (.$taskName) in (.applicationName)",
"Mark (.$taskName) 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"
)
}
}Cụm từ giọng nói phải bao gồm placeholder (.applicationName) để Siri xác định ứng dụng đích. Các tham số động như (.$taskName) cho phép lệnh theo ngữ cảnh.
Intents trong Widget Tương tác
App Intents tích hợp với WidgetKit để tạo widget tương tác. Hiểu các mẫu điều hướng SwiftUI giúp ích khi xây dựng chuyển đổi widget-đến-ứng dụng.
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)
}
}Widget sử dụng cú pháp Button(intent:) để kết nối tương tác trực tiếp với App Intent mà không mở ứng dụng.
Tích hợp Foundation Models Framework
iOS 27 giới thiệu Foundation Models framework, cho phép suy luận LLM trên thiết bị. Mặc dù Foundation Models không có tích hợp Siri trực tiếp, ứng dụng có thể sử dụng nó trong App Intents để xử lý ngôn ngữ tự nhiên hoặc tạo phản hồi.
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 chạy khoảng 30 token mỗi giây trên thiết bị mà không tốn phí mỗi yêu cầu. Framework này yêu cầu iPhone 15 Pro hoặc iPhone 16 trở lên để xử lý trên thiết bị.
Di chuyển từ SiriKit sang App Intents
Đối với ứng dụng vẫn sử dụng SiriKit, việc di chuyển theo quy trình có cấu trúc. Xcode 27 cung cấp công cụ "Convert to App Intent" cho cấu hình Widget, nhưng các handler tùy chỉnh yêu cầu viết lại thủ công.
// 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))
}
}Việc di chuyển loại bỏ các file .intentdefinition và target Intent Extension. Tất cả logic intent chuyển vào target ứng dụng chính dưới dạng struct Swift.
Kiểm thử App Intents
Framework AppIntentsTesting xác thực intents thông qua cơ sở hạ tầng Siri, Shortcuts và Spotlight thực tế mà không cần mock.
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)
}
}Kiểm thử xác minh hành vi intent độc lập với giao diện hệ thống, phát hiện regression trước khi triển khai.
Sources
- Apple WWDC 2026 Announcements : App Intents 2.0 và ngừng hỗ trợ SiriKit
- Swift.org Blog : Các bản phát hành Swift 6.3 và 6.4
- Apple Developer News : Yêu cầu iOS 27 SDK và Foundation Models framework
- iOS 27 App Intents Developer Guide : Chi tiết streaming responses và View Annotations
Danh sách Kiểm tra Triển khai App Intents iOS 27
Đối với ứng dụng nhắm đến iOS 27, App Intents không còn là tùy chọn. Siri AI kết hợp các hành động đa bước giữa các ứng dụng, và ứng dụng không có intents được xuất bản bị loại khỏi các quy trình agentic này.
- Tạo AppIntents cho các hành động chính của ứng dụng
- Định nghĩa AppEntities cho dữ liệu có thể thao tác
- Sử dụng AppEnum cho các kiểu liệt kê
- Triển khai AppShortcutsProvider với cụm từ giọng nói
- Tuân thủ giới hạn tối đa 10 App Shortcuts
- Bao gồm
(.applicationName)trong tất cả cụm từ - Thêm View Annotations vào các view SwiftUI để tham chiếu trên màn hình
- Triển khai streaming responses cho các thao tác chạy lâu
- Hỗ trợ hội thoại multi-turn cho quy trình phức tạp
- Di chuyển từ SiriKit trước khi kết thúc thời gian ngừng hỗ trợ
- Kiểm thử intents với framework AppIntentsTesting
- Bản địa hóa tiêu đề và mô tả
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Bạn có tìm ra lỗi trong iOS không?
Một đoạn mã thật, một lỗi ẩn, mỗi ngày một lượt. Không cần tài khoản để thử.

Viết bởi
Anthony Fillion-MailletNgười sáng lập SharpSkill
Lập trình viên fullstack hơn 10 năm. Anh điều hành SharpSkill và chịu trách nhiệm về mọi nội dung đăng tại đây.
Cập nhật ngày 20 tháng 8, 2026
Thẻ
Chia sẻ
Bài viết liên quan

WidgetKit iOS 17-26: Widget Tương Tác với App Intents
Hướng dẫn đầy đủ tạo widget iOS tương tác với WidgetKit và App Intents. Nút bấm, công tắc, hoạt ảnh, material Liquid Glass iOS 26, và cập nhật WWDC 2026.

Việc làm lập trình viên iOS 2026: Nguồn tuyển dụng, mức lương, cách chuẩn bị phỏng vấn
Hướng dẫn toàn diện tìm việc lập trình viên iOS năm 2026. Khám phá nguồn tuyển dụng, dữ liệu lương thực tế, và chiến lược chuẩn bị phỏng vấn kỹ thuật.

Combine vs async/await trong Swift: Mẫu Hình Di Cư Tiến Bộ
Hướng dẫn đầy đủ về di cư từ Combine sang async/await trong Swift: chiến lược tiến bộ, mẫu hình bắc cầu và sự cùng tồn tại của các mô hình trong codebase iOS.