App Intents 新特性一览
What's new in App Intents
2024年6月10日
一句话判断
App Intents 今年最大的变化是 IndexedEntity 让你的数据能被 Spotlight 语义搜索找到、Transferable 让 Entity 能跨 App 传递——两个改动合在一起意味着你定义一次 Entity,Siri 就能”找到它”并且”把它发给任何人”。
这场 Session 讲了什么
这场 Session 面向已经了解 App Intents 基础的开发者,主讲人 Kenny 介绍了 2024 年框架的四个主要更新。
第一个是 IndexedEntity 协议,让你的 App Entity 能被索引到 Spotlight。过去 Spotlight 只能搜索 CSSearchableItem,现在你的 Entity 直接就能出现 在搜索结果里,而且受益于 Spotlight 新的语义搜索能力。Siri 对你 App 内容的理解也因此大幅提升——她不只是搜索关键词,而是理解内容的语义。
第二个是 Transferable 与 App Entity 的结合。你的 Entity 现在可以声明如何导出为 PDF、图片、富文本等标准格式。这意味着 Siri 和 Shortcuts 可以把你的 App 内容转换后传递给其他 App——比如把一份活动摘要变成附件发到邮件里,或者转成图片存入相册。
第三个是 Universal Links 与 App Intent 的关联。你的 Intent 类型现在可以映射为 Universal Link,设备通过链接就能直接跳转到 App 的对应页面。
第四个是一系列开发者体验改进,简化了 App Intents 的日常使用。
值得深挖的点
IndexedEntity:从”可搜索”到”可理解”
过去让 Spotlight 搜索你的 App 内容,要用 CSSearchableItem 手动构建搜索属性,过程繁琐且与 App Entity 是两套体系。IndexedEntity 直接在 Entity 层面解决了这个问题——你的 TrailEntity 同时就是可搜索的。
实现方式很简洁:Entity 遵循 IndexedEntity 协议后,在 App 初始化时调用 CSSearchableIndex.default().indexAppEntities(entities) 即可完成索引。默认实现会用 DisplayRepresentation 来填充属性集,但你也可以自定义 attributeSet 属性来提供更丰富的信息,比如地理位置、关键词、分类标签等。
这个设计的深层意义在于:它让 Siri 的语义搜索有了真实的 App 数据做支撑。当用户说”帮我找一条在旧金山附近的简单徒步路线”时,Siri 不再只匹配关键词,而是真正理解你每条路线的位置和难度属性。这对 Apple Intelligence 时代的 Siri 体验至关重要。
Transferable + AppEntity:打通 App 间的数据壁垒
Transferable 协议去年已经用于拖拽和分享场景,今年它和 AppEntity 的结合让 Entity 的跨 App 传递变得极其自然。你只需要在 Entity 上实现 transferRepresentation 方法,声明不同导出格式的优先级,Shortcuts 和 Siri 就能自动做格式转换。
有一个设计细节值得注意:导出格式的排列顺序很重要。SDK 要求你从最高保真度到最低保真度排列——先是私有的 Codable 表示,然后是富文本,最后是纯文本。这是因为 Shortcuts 在传递数据时会尝试最高保真度的格式,如果目标 App 不支持才逐级降级。
当前的限制:Xcode 需要在编译时理解你的 Transferable 表示,所以某些动态配置可能不被支持。ProxyRepresentation 只能引用带有 @Property 属性的 Entity 属性。
代码片段
让 Entity 支持 Spotlight 索引
// TrailEntity 遵循 IndexedEntity 协议
struct TrailEntity: AppEntity, IndexedEntity {
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Trail")
static var defaultQuery = TrailEntityQuery()
var id: UUID
var name: String
var location: CLLocation?
var activities: [String]
// 自定义属性集,提供更丰富的搜索信息
var attributeSet: CSSearchableItemAttributeSet {
let set = CSSearchableItemAttributeSet()
set.city = location?.city
set.state = location?.state
set.keywords = activities // 如 ["hiking", "biking"]
return set
}
}
// 在 App 启动时索引所有 Entity
func applicationDidFinishLaunching() {
let trails = TrailDataManager.shared.allTrails()
let entities = trails.map { TrailEntity(from: $0) }
CSSearchableIndex.default().indexAppEntities(entities)
}
一句话说明:IndexedEntity 让你的 Entity 直接成为 Spotlight 的搜索目标,自定义 attributeSet 可以大幅提升搜索准确性。坑在于索引操作是异步的,大量数据时要注意性能。
让 Entity 支持跨 App 格式转换
// ActivitySummary Entity 支持 Transferable
struct ActivitySummary: AppEntity, Transferable {
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Activity Summary")
var id: UUID
var caloriesBurned: Int
var distance: Double
// 从高保真到低保真排列导出格式
static var transferRepresentation: TransferRepresentation {
// 最高保真:私有 Codable 格式
CodableRepresentation(contentType: .activitySummary)
// 中等保真:富文本格式
DataRepresentation(exportedContentType: .rtf) { summary in
try summary.toRichText()
}
// 低保真:PNG 图片
FileRepresentation(exportedContentType: .png) { summary in
try summary.toPNGFile()
}
}
}
一句话说明:格式排列顺序直接决定了 Shortcuts 里”另存为图片”或”追加到笔记”等操作的实际效果。注意 FileRepresentation 返回的是临时文件 URL,不要做持久化假设。
用 IntentFile 读取外部文件内容
struct ProcessDocumentIntent: AppIntent {
static var title: LocalizedStringResource = "Process Document"
@Parameter(title: "Document")
var file: IntentFile
func perform() async throws -> some IntentResult {
// IntentFile 现在支持更丰富的文件类型访问
guard let data = file.data else {
throw IntentError.noData
}
let result = try processDocument(data)
return .result(value: result)
}
}
一句话说明:IntentFile 的改进让 Intent 可以接收更多类型的文件输入,配合 Transferable 的反向使用,Shortcuts 里可以构建完整的文件处理工作流。
最佳实践
新项目:所有 Entity 都直接遵循 IndexedEntity,养成习惯。这不仅让 Spotlight 能搜索到你的内容,也是 Apple Intelligence 理解你 App 的关键通道。有跨 App 分享需求的 Entity 尽早实现 Transferable。
已有项目:优先给核心 Entity 加上 IndexedEntity,这是投入产出比最高的改动——几行代码就能让你的 App 内容出现在 Spotlight 和 Siri 建议里。如果你已有 CSSearchableItem 的索引代码,可以用新的 associateAppEntity() 方法把现有索引和 App Entity 关联起来,不需要推翻重来。
还有什么值得关注
associateAppEntity()方法让你可以在已有的CSSearchableItem上关联 App Entity,已有的 Spotlight 索引代码不用丢弃。- IndexedEntity 支持 priority 设置,你可以让收藏的内容在搜索结果中排名更高。
- App Intent 类型现在可以映射为 Universal Links,这意味着网页链接可以直接触发 App 内的 Intent 操作。