WWDC Quick Look 💓 By SwiftGGTeam
Donate intents and expand your app’s presence

Donate intents and expand your app’s presence

观看原视频

Highlight

Apple 让开发者通过 Intent Donation 把用户在 App 内完成的重复操作交给系统,系统用这些记录在 Siri、Shortcuts、Focus、Smart Stack 和 Suggestions 中展示相关功能。

核心内容

很多 App 的关键功能都藏在界面深处。

用户每天早上查天气、每天上班前点同一杯咖啡、每周固定给同一个人发消息。App 知道这些行为,系统不知道。系统不知道,就无法在锁屏、搜索、小组件堆栈或 Siri 中提前把功能放到用户面前。

以前,开发者可以把功能做成 Shortcuts(快捷指令)动作。问题是,动作本身只说明 App 能做什么。它不一定告诉系统:这个用户什么时候会做、参数是什么、这个动作是否会重复。

Apple 在这场 session 讲的是 Intent Donation(意图捐赠)。当用户在 App 里完成一次操作,App 创建对应的 Intent(意图),填入参数,再通过 INInteraction.donate() 交给系统。系统把这次操作和当时的上下文一起保存,用设备端智能(on-device intelligence)寻找模式。

这样,天气 App 不只提供“查看天气”这个能力。它还能告诉系统:这个用户经常在早上查看 Cupertino 的天气。咖啡 App 不只提供“点咖啡”这个能力。它还能告诉系统:这个用户经常在起床后点 large iced latte。

这件事的结果很直接。App 的功能可以出现在 Smart Stack(智能叠放)、Siri Suggestions(Siri 建议)、Shortcuts、Focus(专注模式)和 Siri 中。用户不必先打开 App,再找到按钮。

捐赠必须代表可重复的动作

Apple 给出的判断标准很严格。

一个动作应该加速用户本来就想做的事。它应该会被多次执行,并且长期对用户有价值。它还应该是无状态的,随时可以执行。

“查看某城市天气”适合捐赠。“删除账户”不适合捐赠。前者会反复发生,后者通常只发生一次。

参数决定系统能不能识别模式

系统会比较 Intent 的参数,判断多次捐赠是否等价。

天气示例里,两次 Cupertino 天气查询会被看作同一类行为。Cupertino 和 San Diego 会被看作不同的行为。这样系统才能分别学习它们出现的时间和场景。

咖啡示例说明了另一个问题。如果把下单日期放进支持预测的参数组合里,今天的 large iced latte 和明天的 large iced latte 会变成两种不同的 Intent。系统就看不到“每天早上点 large iced latte”这个模式。

解决办法是:在 Intent Definition File(意图定义文件)里,只把 itemsize 放进 supported parameter combination(支持的参数组合)。日期可以存在于 Intent 中,但不要让它参与预测等价性的判断。

详细内容

定义可捐赠的 Intent

03:28)第一步是决定使用哪种 Intent。

SiriKit 提供了内置 Intent,覆盖消息、预约、媒体等场景。如果你的动作对应已有的内置 Intent,优先使用内置类型。如果没有匹配项,就在 Xcode 里创建 SiriKit Intent Definition File,定义自定义 Intent。

天气示例使用自定义 CheckWeatherIntent。它包含一个 location 参数,类型是自定义的 City。这个 Intent 勾选了 eligible for widgets(可用于小组件)和 eligible for Siri Suggestions(可用于 Siri 建议)。因为小组件配置需要用户选择城市,location 参数的选项由 App 动态提供。

let intent = CheckWeatherIntent()
intent.location = weatherLocation

let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { (error) in
    // Handle the error.
}

关键点:

  • CheckWeatherIntent() 创建一个自定义天气查询意图,对应 Xcode 中的 Intent Definition File。
  • intent.location = weatherLocation 填入用户刚刚查询的城市,系统用参数区分 Cupertino 和 San Diego 这样的不同操作。
  • INInteraction(intent: intent, response: nil) 把 Intent 包装成一次交互,作为捐赠给系统的对象。
  • interaction.donate 把这次操作交给系统保存。
  • error 回调用于处理捐赠失败,示例没有展开具体错误处理。

系统如何使用捐赠

09:15)捐赠完成后,系统会保存这些记录,以及用户执行操作时的上下文。

天气 App 每次用户查看城市天气时捐赠一次 Intent。系统根据 Intent 参数判断记录是否等价。两个 Cupertino 查询属于同一类,两个 San Diego 查询属于另一类。

随后,系统在设备端用机器学习寻找行为模式。session 中的例子是:用户起床后经常查看天气。系统识别到这个模式后,可以把天气相关能力暴露给前台功能。

let intent = CheckWeatherIntent()
intent.location = weatherLocation

let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { (error) in
    // Handle the error.
}

关键点:

  • 每次用户完成真实操作后再创建 Intent,捐赠记录才反映用户行为。
  • location 是系统判断 Intent 是否等价的关键参数。
  • 同一参数值反复出现,系统才有机会发现可预测的模式。
  • session 明确说明,机器学习和智能处理在设备端完成,Apple 不收集可用于识别个人身份的数据。

删除已经失效的捐赠

09:58)捐赠不是只增不删。

如果用户删除了 San Diego 这个天气地点,继续保留相关捐赠会带来错误建议。系统可能仍然推荐查看 San Diego 天气。Apple 建议在内容失效时删除单条捐赠或一组捐赠。

// Donate your intent.
let interaction = INInteraction(intent: intent, response: response)
interaction.identifier = "68753A44-4D6F-1226-9C60-0050E4C00067"
interaction.groupIdentifier = "san-diego"
interaction.donate { (error) in
    // Handle the error.
}

// Delete individual donations.
INInteraction.delete(with: ["68753A44-4D6F-1226-9C60-0050E4C00067"]) { (error) in
    // Handle the error.
}

// Delete group donations.
INInteraction.delete(with: "san-diego") { (error) in
    // Handle the error.
}

关键点:

  • interaction.identifier 给单次捐赠设置标识,后续可以按标识删除。
  • interaction.groupIdentifier 给一组捐赠设置分组,例如同一个城市 san-diego
  • INInteraction.delete(with: ["68753A44-4D6F-1226-9C60-0050E4C00067"]) 删除指定标识的单条或多条交互。
  • INInteraction.delete(with: "san-diego") 删除同一分组下的捐赠。
  • 删除回调同样返回 error,用于处理删除失败。

让小组件和 Smart Stack 使用捐赠

11:49)天气示例里的 Intent 还可以作为小组件配置。

用户配置天气小组件时,可以选择要显示的城市。App 捐赠的 Intent 与小组件配置 Intent 匹配后,系统就能为 Smart Stack 提供 widget intelligence(小组件智能)。

iOS 15 的 Smart Stack 支持 Widget Suggestions(小组件建议)。如果用户的堆栈里还没有天气小组件,系统可以在合适时间把它建议到堆栈顶部。如果用户已经有天气小组件,系统可以在合适时间轮转到它。

let intent = CheckWeatherIntent()
intent.location = weatherLocation

let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { (error) in
    // Handle the error.
}

关键点:

  • Intent Definition File 中的 “Intent is eligible for widgets” 让 CheckWeatherIntent 可用于小组件配置。
  • location 参数让用户在配置小组件时选择城市。
  • App 持续捐赠同类 Intent 后,Smart Stack 可以利用这些记录判断什么时候展示相关小组件。
  • session 说明,更多小组件智能细节在 WWDC 2021 的 “Add intelligence to your widgets” 中展开。

内置 Intent 带来的系统曝光

13:13)Intent Donation 还会驱动多个系统入口。

自定义 Intent 可以出现在锁屏、Spotlight 搜索和 Siri Suggestions 小组件里,也可以作为 Shortcuts 中的动作使用。内置 Intent 会连接到更具体的系统功能。

Apple 在 session 中列了三个内置 Intent:

  • INSendMessageIntent:用于 sharing suggestions(分享建议),iOS 15 还会用消息对象判断哪些联系人与当前 Focus 强相关。
  • INGetReservationDetailsIntent:用于餐厅预约、航班值机和 Maps 中的一键导航建议。
  • INPlayMediaIntent:iOS 15 会把媒体捐赠显示在锁屏、控制中心和 Home App 的 Now Playing UI 中。
let interaction = INInteraction(intent: intent, response: response)
interaction.identifier = "68753A44-4D6F-1226-9C60-0050E4C00067"
interaction.groupIdentifier = "san-diego"
interaction.donate { (error) in
    // Handle the error.
}

关键点:

  • intent 可以是自定义 Intent,也可以是 SiriKit 的内置 Intent。
  • response 可以随 Intent 一起传入 INInteraction,示例展示了 response: response 的形式。
  • 内置 Intent 的语义由系统理解,因此能接入分享建议、Focus、预约提醒、Now Playing 等系统体验。
  • identifiergroupIdentifier 对内置 Intent 同样有用,便于在内容失效时清理记录。

为媒体内容提供未播放列表

15:32)媒体 App 还有一个额外入口。

如果用户在 App 中消费播客、电视节目或电影这类周期性媒体内容,App 可以使用 INUpcomingMediaManager API 向系统提供用户还没有听过或看过、但可能感兴趣的媒体 Intent 列表。系统会把过去的媒体捐赠和 upcoming media(即将出现的媒体)结合起来,生成更好的媒体建议。

let intent = OrderCoffeeIntent()
intent.item = item
intent.size = size
intent.date = date

let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { (error) in
    // Handle the error.
}

关键点:

  • 这段代码展示的是带参数的 Intent 捐赠结构,媒体 Intent 的捐赠也遵循同样模式。
  • intent.item = itemintent.size = sizeintent.date = date 表示 Intent 可以携带多个参数。
  • 对媒体场景,session 明确提到入口 API 是 INUpcomingMediaManager
  • 系统会结合历史媒体捐赠与 App 提供的未消费媒体列表来生成建议。

用参数组合避免破坏预测

17:13)咖啡示例展示了最容易犯的错误:把会变化的时间戳放进用于预测的参数组合。

用户连续三天点 large iced latte。如果 supported parameter combination 包含 itemsizedate,系统会看到三条不同记录。日期每天变化,记录之间不等价,模式消失。

Apple 给出的修正是:supported parameter combination 只包含 itemsize。这样系统会把三天的 large iced latte 看成等价捐赠,进而发现“起床后点 large iced latte”的模式。

let intent = OrderCoffeeIntent()
intent.item = item
intent.size = size
intent.date = date

let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { (error) in
    // Handle the error.
}

关键点:

  • OrderCoffeeIntent() 是咖啡 App 的自定义 Intent。
  • intent.item = item 表示咖啡品类,例如 session 中的 iced latte。
  • intent.size = size 表示杯型,例如 large。
  • intent.date = date 可以记录一次订单的日期,但不应该放进用于预测等价性的参数组合。
  • Intent Definition File 中的 supported parameter combination 应只包含能稳定代表重复行为的参数。

核心启发

1. 做一个“早晨自动浮现”的天气小组件

  • 做什么:用户每天早上查看某城市天气后,让对应天气小组件在 Smart Stack 中更容易出现。
  • 为什么值得做:session 明确说明,匹配小组件配置 Intent 的捐赠可以驱动 Smart Stack widget intelligence。
  • 怎么开始:创建 CheckWeatherIntent,给它添加 location 参数,勾选 eligible for widgets 和 eligible for Siri Suggestions;用户查看城市天气后调用 INInteraction.donate()

2. 做一个常点咖啡建议

  • 做什么:用户经常点同一杯咖啡时,在 Siri Suggestions 或 Shortcuts 中提供一键下单入口。
  • 为什么值得做:系统会根据重复捐赠和上下文寻找模式,但参数必须稳定。
  • 怎么开始:定义 OrderCoffeeIntent,保留 itemsize 作为预测参数组合;下单成功后捐赠 Intent;不要把每天变化的日期放进 supported parameter combination。

3. 为聊天 App 接入 Focus 联系人建议

  • 做什么:用户经常给同事发消息时,帮助系统在 Work Focus 中建议允许这些联系人通知。
  • 为什么值得做:iOS 15 会使用 INSendMessageIntent 捐赠中的联系人,判断哪些人与当前 Focus 强相关。
  • 怎么开始:在发送消息成功后捐赠 INSendMessageIntent;为会话或联系人设置合适的 groupIdentifier,在会话删除或联系人失效时清理捐赠。

4. 为预约 App 做离店和机场提醒入口

  • 做什么:餐厅预约或航班信息即将到来时,让系统在合适时间给出离开或值机提醒。
  • 为什么值得做:session 明确提到 INGetReservationDetailsIntent 捐赠会用于餐厅预约、航班值机和 Maps 建议。
  • 怎么开始:预约创建后捐赠 INGetReservationDetailsIntent;取消预约时用 identifier 删除对应捐赠。

5. 为播客 App 提供未听剧集建议

  • 做什么:用户打开锁屏或控制中心时,更容易看到还没听的新一期节目。
  • 为什么值得做INPlayMediaIntent 会进入 iOS 15 的 Now Playing UI,INUpcomingMediaManager 可提供未消费媒体列表。
  • 怎么开始:播放媒体时捐赠 INPlayMediaIntent;维护用户未播放内容列表,通过 INUpcomingMediaManager 提供给系统。

关联 Session

评论

GitHub Issues · utterances