Get to know App Intents
Machine Learning & AI 入门 0m

App Intents 框架全面入门

Get to know App Intents

2025年6月9日

在 Apple 官方观看视频

一句话判断

App Intents 已经从”可选的 Shortcuts 集成”变成了 Apple Intelligence 时代 app 的必修课——如果你还没接入,现在是认真考虑的时候了。

这场 Session 讲了什么

这场 Session 是 App Intents 框架的从零入门,从最基础的 intent、entity、query 三个核心概念讲起,一路延伸到 App Shortcut、Spotlight 索引、SwiftUI 导航集成等进阶用法。主讲人用一个地标浏览 app 做贯穿始终的 demo,逐步构建出一个能在 Spotlight、Siri、Action Button 中被调用的完整意图体系。

框架的核心思路是把 app 的功能抽象成”动词”(intent)和”名词”(entity),然后通过 query 让系统理解你的数据。今年的更新集中在几个方面:entity 属性支持 @ComputedProperty 从已有 model 延迟取值而不需要拷贝;Spotlight 支持在属性上直接标注索引 key;新增 Target Content Providing Intent 协议配合 onAppIntentExecution modifier 实现声明式导航;以及 App Intents 终于支持 Swift Package 和 static library 中定义类型。

整个框架的设计哲学很清晰:编译时读取源码生成元数据,零配置文件,app 安装后系统无需启动 app 就能理解你的能力。这意味着你的 intent title 必须是常量,不能是计算属性——这是 build-time processing 决定的硬约束。

值得深挖的点

Entity Query 的设计哲学与性能陷阱

Entity Query 是 App Intents 里最容易被低估的部分。表面上它只是”按 ID 查找 entity”,但实际承载了系统向你的 app 提出的所有数据问题:有哪些 entity?哪些 entity 匹配这个字符串?哪些 entity 满足这些 predicate?

Query 的核心方法是 entities(for:),系统通过它按 ID 获取 entity 实例。这个设计保证了系统可以引用 entity 而不必立即加载其完整数据——懒加载是性能的关键。如果你的 entity 有图片、富文本等重资源,千万不要在 entity 初始化时就加载,全部推迟到 query 被调用时再处理。

但这里有个 trade-off:suggestedEntities 方法如果返回全量数据,在 entity 数量上千时会成为瓶颈。Apple 的建议是针对内存能放下的场景用 EnumerableEntityQuery,否则实现 EntityStringQuery 做按需搜索。对于大型数据集,更实际的做法是只在 suggestedEntities 里返回用户收藏或最近使用的子集,把完整搜索留给 string query。

另一个容易踩的坑是 @Dependency 注入。依赖需要在 app 生命周期早期通过 AppDependencyManager 注册,如果注册时机晚于系统首次查询 entity,就会 crash。建议在 init()didFinishLaunching 里一次性完成。

跨 Target 共享 App Intents 类型的正确姿势

今年新增了 Swift Package 和 static library 支持,但跨 target 共享类型需要额外的 AppIntentsPackage 注册。这个机制的存在是因为 App Intents 在 build-time 扫描每个 target 的源码生成元数据,如果多个 target 引用了同一个类型,运行时需要知道这个类型属于哪个 package。

实际操作中,常见架构是把 Entity 定义在 Swift Package 里,app target 和 extension 各自声明自己的 AppIntentsPackage 并引用 package 里的类型。如果不做这一步,运行时会因为类型解析失败而静默不工作——没有编译错误,只有运行时找不到 intent 的诡异行为。

Trade-off 在于:如果你只有一个 app target,完全不需要关心 package 注册。但一旦拆分出 extension 或引入共享 package,就必须显式管理依赖关系。建议从一开始就用 package 管理 entity 类型,避免后续重构。

代码片段

1. 基础 Intent 定义

场景:创建一个打开 app 特定页面的 intent。

struct OpenLandmarksIntent: AppIntent {
    static var title: LocalizedStringResource = "Open Landmarks"
    static var supportedModes: IntentModes = .foreground

    @MainActor
    func perform() async throws -> some IntentResult {
        Navigator.shared.open(.landmarks)
        return .result()
    }
}

坑:title 必须是 LocalizedStringResource 字面量,不能用变量或计算属性,否则 build-time 元数据生成会失败。

2. 带参数的 Entity 和 ComputedProperty

场景:用地标 entity 暴露给 Shortcuts,属性直接引用已有数据模型。

struct LandmarkEntity: AppEntity {
    static var title = LocalizedStringResource("Landmark")
    static var defaultQuery = LandmarkQuery()

    let id: String

    @ComputedProperty
    var name: String { model.name }

    @ComputedProperty
    var state: String { model.state }

    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(name)")
    }
}

坑:@ComputedProperty 是今年新增的,避免了手动在 entity 和 model 之间拷贝属性值。但如果底层 model 不是线程安全的,在并发场景下可能产生数据竞争。

3. App Shortcut 定义

场景:注册一个可通过 Siri 和 Spotlight 直接触发的快捷指令。

struct LandmarkShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: OpenLandmarksIntent(),
            phrases: [
                "Open \(\.$appName) Landmarks",
                "Show landmarks in \(\.$appName)"
            ],
            shortTitle: "Open Landmarks",
            systemImageName: "map"
        )
    }
}

坑:每个 phrase 必须包含 applicationName placeholder。带参数的 phrase 会自动为每个 suggested entity 值生成一个 App Shortcut,entity 数量多时要注意控制。

最佳实践

  • 先用 App Shortcut 把核心功能暴露给系统,再逐步丰富 entity 和 query。
  • entity 的 id 必须是持久化的、可用于数据库查找的标识符,不要用临时值。
  • 给 entity 实现 Transferable 协议,让 Shortcuts 能在 app 间传递图片等资源。
  • 把高频使用的 entity 实现 IndexedEntity,让 Spotlight 能语义搜索你的内容。
  • Target Content Providing Intent + onAppIntentExecution 替代手动导航逻辑,实现声明式 intent 处理。
  • 依赖注册放在 app 启动的最早时机,避免系统查询时依赖尚未就绪。

还有什么值得关注

  • Spotlight on Mac 现在可以从任意位置调用你的 app action,前提是你实现了带完整 required 参数的 ParameterSummary
  • updateAppShortcutParameters 方法可以基于用户偏好动态更新 App Shortcut 的参数化短语,实现个性化 Siri 触发。
  • App Intents 的元数据是 build-time 生成并嵌入 app 的,不需要任何配置文件或运行时注册——这意味着如果你的 macro 或 computed property 在 title 里用了非字面量,编译器会直接报错而不是运行时崩溃。
机器学习