Highlight
Siri 在 iOS 27 中通过 App Schemas 获得了理解 App 内容、执行跨 App 操作和感知屏幕上下文的能力。开发者只需将现有数据建模为 AppEntity、接入系统预定义的 Schema 并标注视图,即可让 Siri 用自然语言搜索、操作和流转 App 内容。
核心内容
以前让 Siri 控制 App,开发者得自己处理自然语言解析,写一堆自定义 Intent,用户还得记住固定说法。体验生硬,覆盖场景有限。
今年 Apple Intelligence 让 Siri 变成了真正能”看懂”App 的助手。它不再把 App 当黑盒,而是直接理解 App 里的实体(Entity)是什么、能做什么动作、屏幕上显示了什么。开发者不需要自己处理语言理解,只需要描述清楚 App 的数据结构和能力,Siri 负责把用户的话翻译成具体操作。
这个转变的核心是 App Schemas。App Schemas 是系统预定义的概念集合,比如消息、联系人、文档。当开发者的 AppEntity 遵循某个 Schema 时,Siri 已经知道这个概念的含义、属性和常用操作,不需要从头学习。
举个例子:用户说”给 Glow 发消息问有什么电影推荐”。Siri 知道”发消息”对应 messages domain 的 sendMessage schema,知道”Glow”是一个联系人实体,知道”有什么电影推荐”是消息内容。它自动完成实体解析、参数填充和意图执行,App 只负责真正发送消息。
更厉害的是跨 App 操作。用户可以说”把这条回复邮件发给我老婆”,Siri 先理解屏幕上”这条回复”指的是哪个消息实体,再把它导出为系统能理解的格式,传给邮件 App 执行发送。整个流程涉及屏幕感知、内容导出、跨 App 流转三个环节,开发者只需要标注视图和实现 Transferable 协议。
Siri 的三项新能力
理解 App 内容(01:57):Siri 现在能直接访问 App 的实体。用户问”我下一场会议在什么时候、在哪里”,Siri 能识别出”会议”这个实体类型,找到最相关的那一个,返回时间和地点属性。
执行 App 动作(02:19):用户说”把最新报告发给 Mary”,Siri 解析出”发送”动作、“最新报告”实体和”Mary”收件人,调用 App 的 sendMessage intent 完成操作。
感知屏幕上下文(02:44):用户指着屏幕说”解释这段文字”或”查这个产品的评价”,Siri 通过视图标注知道屏幕上显示了什么内容,把”这段文字""这个产品”解析成具体实体。
语义搜索 vs 字符串查询
大部分场景下,IndexedEntity 是首选。它把实体属性索引到系统语义索引中,Siri 能基于含义匹配,而不是逐字匹配。用户说”Flare 上次说关于电影的事”,Siri 能找到提到电影的消息,即使消息里没有”电影”这个词。
但 IndexedEntity 不适合所有情况。数据量大、存在服务端、变化频繁的数据,用 EntityStringQuery 更合适。Siri 把用户输入的字符串交给 App,App 自己决定怎么搜索和匹配。代价是失去了语义理解能力,但获得了完全的控制权。
屏幕感知的两种 API
一种情况是屏幕上只有一个主要内容,比如看文档、写邮件。用 NSUserActivity 标记当前活动,Siri 知道”这个”指的是什么。
另一种情况是屏幕上同时显示多个内容项,比如聊天列表、商品列表。用 .appEntityIdentifier 修饰符给每个列表项绑定对应的实体标识。Siri 能区分”这条消息”和”那条消息”,支持”转发最后一条”这种指令。
内容流转的两种模式
内容从其他 App 进入你的 App 时,有两种处理方式。如果内容对应 App 里已有的数据,用 IntentValueQuery 把它解析成现有实体。如果内容应该创建新数据,用 Transferable 的 importing 闭包把传入值转换成新实体。很多 App 两种都用,取决于具体场景。
详细内容
用 AppEntity 建模数据
AppEntity 用描代替新数据模型,述现有数据的方式。它回答三个问题:这个东西是什么、怎么识别它、哪些属性重要。
以 UnicornChat 为例,App 里有 Contact(联系人)、Conversation(对话)、Message(消息)三种实体。每种都遵循对应的 App Schema:
@AppEntity(schema: .messages.message)
struct MessageEntity: IndexedEntity {
// 告诉 Spotlight 哪些属性参与语义搜索
@Property(indexingKey: \.textContent)
var body: AttributedString?
}
关键点:
@AppEntity(schema: .messages.message)把 MessageEntity 绑定到 messages domain 的 message schema,Siri 立刻知道这是”消息”概念IndexedEntity协议让系统为 body 属性建立语义索引indexingKey指定参与语义搜索的属性,Siri 能基于含义而非字面匹配找到内容
字符串查询兜底
当数据无法索引时,实现 EntityStringQuery:
struct ContactQuery: EntityStringQuery {
func entities(matching string: String) async throws -> [ContactEntity] {
let predicate = #Predicate<Person> { person in
person.name.localizedStandardContains(string)
}
let descriptor = FetchDescriptor<Person>(predicate: predicate)
let matches = try modelContext.fetch(descriptor)
return matches.map(\.entity)
}
}
关键点:
EntityStringQuery协议要求实现entities(matching:)方法- Siri 把用户的自然语言输入原样传入,App 负责查找匹配实体
- 示例中使用 SwiftData 的
FetchDescriptor和#Predicate做本地查询 - 返回
[ContactEntity]让 Siri 继续后续操作
标注屏幕内容
让 Siri 理解列表中每个条目对应哪个实体:
List {
ForEach(messages) { message in
MessageRow(message: message)
.appEntityIdentifier(
EntityIdentifier(
for: MessageEntity.self,
identifier: message.id
)
)
}
}
关键点:
.appEntityIdentifier是 SwiftUI 视图修饰符,把 UI 元素和 AppEntity 关联EntityIdentifier需要指定实体类型和唯一标识符- 用户说”编辑这条消息”时,Siri 从视图标注中解析出具体是哪个 MessageEntity
- 只有当前渲染在屏幕上的列表项会被标注,LazyVStack 中屏幕外的项 Siri 感知不到
导出实体供其他 App 使用
让其他 App 能操作你的内容:
extension ContactEntity: Transferable {
static var transferRepresentation: some TransferRepresentation {
IntentValueRepresentation(
exporting: \.person
)
}
}
关键点:
Transferable协议让实体可以在 App 间流转IntentValueRepresentation定义导出格式,这里把 ContactEntity 导出为系统标准的 IntentPerson- 导出后,其他 App 的 Intent 可以接收这个联系人,比如”给这个联系人打电话”
导入内容创建新实体
接收其他 App 传来的内容并创建新数据:
extension ContactEntity: Transferable {
static var transferRepresentation: some TransferRepresentation {
IntentValueRepresentation(
exporting: \.person,
importing: { intentPerson in
let contact = Contact(importing: intentPerson)
ContactManager.shared.contacts.append(contact)
return contact.entity
}
)
}
}
关键点:
importing闭包在收到外部内容时执行- 把系统标准的 IntentPerson 转换成 App 内部的 Contact 模型
- 添加到 ContactManager 后返回对应的 ContactEntity
- 注意线程安全:如果 ContactManager 绑定 MainActor,importing 闭包中需要正确处理 Actor 隔离
解析传入的 Intent 值
当其他 App 传来的内容应该匹配已有数据时:
struct ContactEntityQuery: IntentValueQuery {
func values(for input: [IntentPerson]) async throws -> [ContactEntity] {
let names = input.map(\.displayName)
let descriptor = FetchDescriptor<Contact>()
let contacts = try model.mainContext.fetch(descriptor)
let matches = contacts.filter { contact in
names.contains(where: { name in
contact.name.localizedStandardContains(name)
})
}
return matches.map(\.entity)
}
}
关键点:
IntentValueQuery协议用于把传入的系统值解析成 App 实体- 示例中接收
[IntentPerson],按 displayName 匹配本地 Contact - 使用
localizedStandardContains做本地化模糊匹配 - 返回解析后的
[ContactEntity]供 Intent 使用
Xcode Fix-It 补全 Schema
Xcode 会检查 Schema 的完整性。如果实现了 sendMessage,但没实现相关的 draftMessage,编译时报错并生成补全代码:
// Xcode Fix-It 生成的 draftMessage 骨架
@main
struct DraftMessageIntent: AppIntent {
static var title: LocalizedStringResource = "Draft Message"
@Parameter
var recipient: ContactEntity?
@Parameter
var content: String?
@MainActor
func perform() async throws -> some IntentResult {
// 打开消息创建界面
return .result()
}
}
关键点:
- 某些 Siri 场景需要多个相关 Schema 配合才能完成完整体验
- Xcode 在编译期暴露缺失的 Schema,而不是运行时静默失败
- Fix-It 生成完整的 Intent 定义、参数声明和骨架实现
- 开发者只需填充 App 特定的业务逻辑
核心启发
做一个 Siri 能”看懂”的笔记 App
做什么:让用户用自然语言搜索笔记,比如”找上周关于预算的笔记”,Siri 基于语义索引返回结果。
为什么值得做:IndexedEntity 让本地笔记内容进入系统语义索引,用户不需要记住笔记标题或标签。
怎么开始:把 Note 模型包装成遵循 AppEntity(schema: .notes.note) 的实体,给 content 和 title 属性加 indexingKey,实现 EntityStringQuery 作为云端笔记的兜底方案。
做一个支持跨 App 流转的待办 App
做什么:用户在邮件 App 里看到任务,说”把这个加到待办列表”,Siri 把邮件内容解析成待办事项。
为什么值得做:Transferable + importing 让其他 App 的内容无缝流入你的 App,用户不需要手动复制粘贴。
怎么开始:让 TodoEntity 遵循 Transferable,实现 IntentValueRepresentation 的 importing 闭包,把传入的文本或 URL 转换成 Todo 对象。
做一个屏幕感知的图片编辑 App
做什么:用户选中一张图片说”给这张加个电影滤镜”,Siri 知道”这张”指的是当前屏幕上选中的图片。
为什么值得做:.appEntityIdentifier 让 Siri 精确识别屏幕上的内容,支持”这个""那个”这种自然指代。
怎么开始:给图片网格中的每个 Image 视图加 .appEntityIdentifier,绑定到 PhotoEntity,实现 applyFilter 的 AppIntent。
做一个 Schema 完整的邮件客户端
做什么:完整接入 messages domain,支持发送、草稿、搜索等全套 Siri 操作。
为什么值得做:Xcode 会引导你补全整个 domain 的所有 Schema,实现后 Siri 对邮件的操作体验与系统原生邮件一致。
怎么开始:从 sendMessage schema 开始,Xcode Fix-It 会提示缺少哪些相关 Schema,逐个实现即可。
关联 Session
- Session 242: Build agentic apps with Apple Intelligence — 讲解如何构建具备自主决策能力的 Agentic App,与 App Schemas 的 Intent 系统互补
- Session 295: Validate your App Intents adoption with AppIntentsTesting — 专门介绍 AppIntentsTesting 测试框架,Session 240 末尾提到的测试工具
- Session 310: What’s new in Shortcuts — Shortcuts 是验证 App Intent 参数映射和界面展示的重要测试环节
- Session 345: What’s new in App Intents — App Intents 基础能力的年度更新,是理解 App Schemas 的前置知识
- Session 343: Dive deep into App Intents — 深入讲解 App Intents 高级用法,包括复杂参数和意图链
评论
GitHub Issues · utterances