WWDC Quick Look 💓 By SwiftGGTeam
Add configuration and intelligence to your widgets

Add configuration and intelligence to your widgets

观看原视频

Highlight

WidgetKit 在 iOS 14 和 macOS Big Sur 通过 Intent 配置、Siri Suggestions 捐赠和 TimelineEntryRelevance,让同一个 widget 实例显示用户选择的内容,并帮助 Smart Stack 在相关时机把它转到顶部。

核心内容

很多 widget 的第一版都能展示信息,但用户很快会遇到第二个问题:同一个 App 里有多份内容,Home Screen 上只想看其中一份。交易 App 的例子很典型。用户可能有多张卡,Recent Purchases widget 只应该显示其中一张卡的交易,也可能只想看食品或交通这类分类。

如果每个选择都要开发者自己做设置页,widget 会变重。Apple 采用了另一条路径:开发者在 Intent Definition File 里声明参数,系统根据这些参数生成 widget 背面的配置界面。用户长按 widget、点 Edit Widget,就能选择 Card 和 Category。配置后的 intent 实例会在运行时传给 widget extension。(03:24

配置解决的是“显示哪一份内容”。智能调度解决的是“什么时候显示”。Smart Stack 会根据用户行为和 App 提供的相关性信号,把合适的 widget 转到栈顶。天气 App 里即将到来的雷暴、交易 App 里超过 50 美元的消费,都是 session 里给出的具体场景。(17:43

这场 session 的关键,是把配置和智能调度连起来。用户在 widget 上选择了某张卡;App 在用户查看同一张卡时捐赠 intent;系统学习这个时间规律;当同一张卡的 widget 已经存在于 Smart Stack 里,系统就有机会在正确时间把它显示出来。(20:04

详细内容

用 Intent 定义 widget 配置项

03:24)Widget 的配置界面来自 intent。Intent 包含一组有顺序的参数,每个参数都会变成配置 UI 上的一行。演示里的 ViewRecentPurchasesIntent 有两个参数:CardCategory

Intent Definition File
ViewRecentPurchases intent

parameters:
  Card      -> custom Card type
  Category  -> enum, default value: All

eligible:
  Intent is eligible for widgets

关键点:

  • Intent Definition File 是 Xcode 里声明 intent、参数和类型的位置。
  • Intent is eligible for widgets 让这个 intent 可以作为 widget 配置。
  • Card 用自定义类型,因为它代表 App 内部的一张卡。
  • Category 用枚举,因为分类集合是固定的。
  • Xcode 会生成 intent class,例如 ViewRecentPurchasesIntent,里面有对应参数属性。

给配置项提供动态选项

09:40)很多配置值不能写死在 Intent Definition File 里。信用卡列表会随登录用户变化,所以 Card 参数需要动态选项。打开 Dynamic Options 后,系统会生成 intent handler protocol,要求 App 或 Intents extension 提供候选值。

Card parameter
  Dynamic Options: on

generated methods:
  provideCardOptionsCollection
  defaultCard

runtime data:
  app cards -> custom Card objects -> INObjectCollection -> completion handler

关键点:

  • provideCardOptionsCollection 返回用户可选的 Card 列表。
  • defaultCard 返回第一次添加 widget 时使用的默认 Card。
  • INObjectCollection 可以返回平铺列表,也可以按 section 分组。
  • 开启搜索后,provideCardOptionsCollection 会收到 search term,用户输入时可以返回额外搜索结果。
  • 默认值很重要,因为新 widget 拖到 Home Screen 时会先显示默认 Card 的内容。

从 StaticConfiguration 切到 IntentConfiguration

13:47)配置项定义好后,widget extension 要从静态配置改成 intent 配置。Provider 也要改成 IntentTimelineProvider,这样 timeline 方法会收到用户选好的 intent 参数。

Widget definition:
  StaticConfiguration
    -> IntentConfiguration(intent: ViewRecentPurchasesIntent)

Timeline provider:
  TimelineProvider
    -> IntentTimelineProvider

timeline input:
  intent.card
  intent.category

关键点:

  • IntentConfiguration 告诉 WidgetKit 这个 widget 用哪一个 intent 做配置。
  • IntentTimelineProvider 的方法会多拿到一个 intent 参数。
  • widget 不再只显示默认卡片,而是根据 intent.card 选择交易数据。
  • intent.category 可以继续过滤交易列表。
  • 同一个 widget 类型可以有多个实例,每个实例保存不同配置。

定制配置页的文字、颜色和参数关系

15:13)系统生成配置 UI,不代表开发者完全不能调整。Widget extension 可以设置配置页标题和描述;asset catalog 和 build settings 可以设置配置页的 accent color 和 background color;Intent Definition File 可以让某个参数依赖另一个参数。

configuration UI customization:
  configurationDisplayName
  description
  Global Accent Color Name
  Widget Background Color Name

parameter relationship:
  Mirror Calendar App = false
    -> show Calendar parameter

关键点:

  • configurationDisplayNamedescription 会显示在 widget 配置相关界面。
  • 命名颜色放在 widget extension 的 asset catalog 里。
  • Global Accent Color Name 控制 accent color。
  • Widget Background Color Name 控制 widget 背面背景色。
  • 父子参数关系适合 Calendar 例子:关闭 Mirror Calendar App 后,才显示手动选择 Calendar 的参数。

用 intent donation 帮 Smart Stack 学习用户习惯

19:13)Smart Stack 会根据用户行为把 widget 转到顶部。iOS 14 让 Shortcuts 和 custom intent donations 也能影响 widget 的展示时机。演示里,用户在 App 里查看某张卡的近期消费时,host app 捐赠同一个 ViewRecentPurchasesIntent

setup:
  mark intent eligible for Siri Suggestions
  Supported Combinations: Card

host app behavior:
  user views recent purchases for AcmeCard
  create INInteraction with ViewRecentPurchasesIntent
  donate interaction

prediction:
  system predicts Card at the learned time
  matching configured widget can surface in Smart Stack

关键点:

  • Intent is eligible for Siri Suggestions 让系统可以预测这个 intent。
  • Supported Combinations 指定哪些参数对预测有意义。
  • 只选择 Card 时,Category 不参与匹配,显示 AcmeCard 的 widget 都有机会被转到顶部。
  • 同时选择 Card 和 Category 时,只有两个参数都匹配的 widget 才会被系统考虑。
  • 捐赠发生在 host app 里,时机是用户实际查看对应信息的时候。

用 TimelineEntryRelevance 标记重要内容

23:33)系统还会根据 timeline entry 的相关性判断是否展示 widget。TimelineEntryRelevance 包含 scoreduration。演示把超过 50 美元的消费视为高相关事件,用更高分数告诉系统这条 entry 更值得显示。

TimelineEntry:
  date timestamp
  rendered view
  relevance: TimelineEntryRelevance

TimelineEntryRelevance:
  score
  duration

score examples:
  1.0  -> purchase over $50
  0.1  -> minor purchase
  0.0  -> no recent purchase

关键点:

  • score 只和同一个 widget 过去提供的分数比较,不和其他 App 的 widget 比较。
  • score 小于或等于 0 表示当前没有相关信息,不应该被转到顶部。
  • duration 适合比分直播这类有明确时间窗口的内容。
  • duration 为 0 时,相关性会持续到下一次收到 relevance。
  • 如果一次 timeline 更新不想改变相关性,可以把 TimelineEntryRelevance 留空。

核心启发

1. 做一个可选择账户的余额 widget

做什么:让用户在 Home Screen 上放多个余额 widget,每个实例显示一张卡、一个账户或一个钱包。

为什么值得做:session 的交易 App 例子就是为不同 Card 创建多个 Recent Purchases 或 Due Date widget。

怎么开始:在 Intent Definition File 里定义账户参数,打开 Dynamic Options,用 provideCardOptionsCollection 返回当前用户的账户列表,再把 widget 改成 IntentConfiguration

2. 做一个按分类过滤的近期记录 widget

做什么:让用户选择“食品”“交通”“订阅”等分类,widget 只展示对应记录。

为什么值得做Category 是演示里的第二个参数,默认值是 All,适合从全量记录逐步收窄。

怎么开始:把分类做成 enum 参数,给它设置默认值,再在 IntentTimelineProvider 中用 intent 参数过滤 timeline entry 的数据。

3. 给 Smart Stack 捐赠用户常看的内容

做什么:当用户每天中午查看某个项目、账户或课程时,让系统学习这个习惯,把对应 widget 在 Smart Stack 里提前显示出来。

为什么值得做:transcript 里的 AcmeCard 例子说明,系统会用 donated intent 识别用户常在某个时间寻找的信息。

怎么开始:把配置 widget 的 intent 标记为 Siri Suggestions eligible,设置只包含关键参数的 Supported Combinations,在 host app 里用 INInteraction 捐赠用户刚查看的 intent。

4. 为强时效事件设置 relevance score

做什么:当订单超额、航班登机、比赛开始、暴雨预警这类事件出现时,让 widget 更容易被系统转到顶部。

为什么值得做TimelineEntryRelevancescore 表示 entry 相对于本 widget 历史内容的重要程度,分数高的 entry 更适合 Smart Stack。

怎么开始:先定义一套自己的分数规则,例如无事件为 0、普通更新为 0.1、重要事件为 1,再在 timeline entry 上附加 relevance。

5. 为固定时长的活动设置 duration

做什么:给比赛、会议、直播课、限时促销这类活动设置相关性窗口,活动结束后不再继续占用 Smart Stack 机会。

为什么值得做:session 的篮球 widget 例子把比赛开始到结束作为固定 duration,期间的后续更新可以不改变 relevance。

怎么开始:生成活动开始时的 timeline entry,设置 TimelineEntryRelevancescoreduration;后续比分或状态更新如果只改 UI,就把 relevance 留空。

关联 Session

评论

GitHub Issues · utterances