What's new in App Intents
App Intents 进阶 40m

App Intents 新特性

What's new in App Intents

2025年6月12日

在 Apple 官方观看视频

一句话判断

如果你现在还不给应用加 App Intents,等 Apple Intelligence 在国内落地那天,你的应用在 Siri 里就是隐形的。

这场 Session 讲了什么

App Intents 从 iOS 16 到现在一直被大多数开发者当成”给快捷指令加个入口”的边角功能,做不做无所谓。这次 WWDC 把它推到了完全不同的位置:你的 Intent 不再只是被用户手动触发的指令,而是会被 Apple Intelligence 主动发现和调度的能力单元。区别在于,以前用户必须说对关键词才能触发你的功能,现在系统会根据你写的自然语言描述去”理解”你的应用能做什么,然后自动匹配用户的模糊请求。

参数系统也从”声明类型就完事”升级成了带验证、带依赖、带异步选项的完整契约。你可以告诉系统”这个时间不能早于现在”、“这两个参数有联动关系”,系统会在执行前帮你校验。DynamicOptionsProvider 终于支持异步了——参数选项可以实时从网络拉取,不用再写死在代码里。

另一个大变化是实体的跨会话记忆。旧版 AppEntity 的标识在会话结束后就丢了,Siri 每次都得重新问用户”你说的是哪个”。现在系统可以跨会话追踪同一个实体,用户说”上次那篇笔记”,Siri 真的能找回来。这看起来是个小改动,但它让 AI 交互从”单轮对话”变成了”有上下文的连续对话”,体验差距很大。

值得深挖的点

@IntentDescription 的语义博弈

@IntentDescription 是这次最核心的新 API,但它的设计里藏着一个有意思的 tension。一方面,苹果鼓励你用自然语言详细描述 Intent 的能力——描述越精准,AI 匹配越准。另一方面,描述是你面向 AI 的”广告文案”,你有动机把描述写得尽可能宽泛,让自己的 Intent 被更多请求命中。

举个例子:一个天气应用的 Intent,你可以写”查询指定城市的天气预报”,也可以写”回答用户关于天气、温度、湿度、穿衣建议的任何问题”。后者显然能覆盖更多场景,但如果所有应用都这么写,系统的语义匹配就会退化成关键词竞价。

苹果目前没有在 Session 里提到任何防滥用机制——没有描述长度限制,没有语义相似度检测,没有去重策略。这要么是还没做,要么是他们信任开发者不会乱来。我的判断是:早期苹果会放任,等规模上来后再加约束。所以现在的策略应该是写得精准而不是宽泛——你先建立良好的匹配记录,后面调整策略时不会被动。

持久化实体标识的实际坑

跨会话实体追踪听起来很美,但落地时有一个容易忽略的问题:你的实体 ID 到底有多”持久”。Session 里强调要用数据库主键而不是临时 UUID,这没问题。但很多应用的实体 ID 并不是真正不变的——CloudKit 同步时可能合并冲突记录,用户在不同设备上创建的同名实体可能被去重,甚至用户卸载重装后本地数据库重建,ID 都可能变。

更微妙的是,Siri 记住的是”上次那篇笔记”这个语义关联,而不是直接存你的 ID。系统内部一定有一层从语义到实体的映射,这个映射的失效策略是什么?Session 没有讲。如果你的实体被删除了,Siri 是报错还是静默降级?这些边界情况在实际开发中一定会遇到,建议在 beta 阶段就做充分测试。

代码片段

用 @IntentDescription 暴露语义能力

场景:照片应用希望 Siri 能理解”把照片发给妈妈”并自动匹配分享 Intent。

@IntentDescription("将指定照片分享给联系人,支持通过消息或邮件发送")
struct SharePhotoIntent: AppIntent {
    static var title: LocalizedStringResource = "分享照片"

    @Parameter(title: "照片", description: "要分享的照片")
    var photo: PhotoEntity

    @Parameter(title: "收件人", description: "接收照片的联系人")
    var recipient: PersonEntity

    func perform() async throws -> some IntentResult {
        try await ShareService.share(photo, to: recipient)
        return .result()
    }
}

坑:@IntentDescription 的描述既要让 AI 理解,又不能太宽泛导致误匹配,建议写”做什么 + 对谁 + 方式”三要素。

持久化实体与跨会话查询

场景:笔记应用希望 Siri 能记住用户上次提到的笔记,即使应用重启也能引用。

struct NoteEntity: AppEntity {
    static var typeDisplayRepresentation: TypeDisplayRepresentation = "笔记"
    let id: String  // 必须是数据库主键,不能用 UUID()
    var title: String

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

struct NoteQuery: EntityQuery {
    func entities(for identifiers: [String]) async throws -> [NoteEntity] {
        try await NoteStore.shared.fetchNotes(ids: identifiers)
    }

    func suggestedEntities() async throws -> [NoteEntity] {
        try await NoteStore.shared.recentNotes(limit: 5)
    }
}

坑:suggestedEntities() 的返回顺序直接影响 Siri 推荐,别返回全量数据,按最近使用排序。

带异步选项的参数验证

场景:提醒事项应用需要从网络获取用户的历史提醒作为选项,同时验证时间不能早于现在。

struct CreateReminderIntent: AppIntent {
    static var title: LocalizedStringResource = "创建提醒"

    @Parameter(title: "提醒内容", optionsProvider: RecentReminderProvider())
    var content: String

    @Parameter(title: "提醒时间")
    var reminderTime: Date

    func validate() async throws -> Bool {
        guard reminderTime > .now else {
            throw $reminderTime.needsValueError("提醒时间不能早于当前时间")
        }
        return true
    }

    func perform() async throws -> some IntentResult & ProvidesDialog {
        let reminder = try await ReminderStore.shared.create(
            content: content, time: reminderTime
        )
        return .result(dialog: "已创建提醒:\(content)")
    }
}

坑:validate() 的错误信息会直接展示给用户和 Siri,写中文时注意语气温和,别用”错误:XXX”这种开发者风格。

最佳实践

先盘点应用里最常被用户手动操作的 3 个功能,给它们加上 App Intents。不用一步到位,先让 Siri 能”看到”应用。

然后花一个下午认真写 @IntentDescription——这玩意现在就是面向 AI 的 SEO,写得好不好直接决定用户能不能通过 Siri 找到你的功能。写完之后用新的 Intent Testing 框架跑一遍,确保参数验证和实体查询在边界条件下不会崩。

最后,如果还在用 INIntent 那套老 API,现在就该迁移了。老 API 不会获得 Apple Intelligence 集成能力,等于主动放弃了在 AI 时代的入口。

还有什么值得关注

  • Visual Intent 反馈:Intent 执行时可以在界面展示应用自定义的实时视觉效果,用户终于能看到 AI 操作到底在干什么,不再是黑盒。
  • Intent Testing 框架:XCTest 原生支持 App Intent 测试了,终于不用靠 Shortcuts 手动验证每个 Intent 的行为了。
  • DynamicOptionsProvider 异步化:参数选项可以实时从网络获取,这对那些选项列表会动态变化的应用(比如联系人、标签、分类)是刚需。
App Intents Siri Shortcuts Apple Intelligence AI