Cff45359701ead286b22f3075631eefe
WWDC20 10194 - 使你的 Widget 支持个性化配置 & 智能化展现

本文基于 WWDC 2020 - Add configuration and intelligence to your widgets 编写

在阅读本文前,推荐先对新的 Widget 系统有个大致的了解,同时也推荐先熟悉 Apple 在 SiriKit 中引入的 Intents API。

推荐阅读:
WWDC 2020 - Meet WidgetKit
WWDC 2020 - Widgets Code-along
WWDC 2016 - Introducing SiriKit
WWDC 2018 - Introduction to Siri Shortcuts

概述

在 WWDC 2020 中,Apple 引入了 Widget (小挂件)这一全新的 App Extension,允许开发者在设备主屏幕、“今天”视图和 macOS 通知中心上显示自定义的小挂件。

该 session 首先介绍了如何通过 Intents API,让我们开发的 Widget 支持让用户进行个性化配置,并介绍了目前支持的配置参数的类型,如何自定义参数类型,并且支持为用户动态生成待选项列表。

之后介绍了 Widget 支持在 Smart Stack 中堆叠展示,同时可以通过开发者的配置让 Widget 智能地被系统展现:

  1. 通过复用 Intents 的“捐赠(donate)”的概念,让用户在合适的时机看到 TA 需要的内容。
  2. 通过为特定的 TimelineEntry 指定相关性信息,让用户能及时看到开发者认为和当前用户高度相关的内容。

让我们开始吧~

知识导图

基本概念

为了更好的解释相关概念,这个 session 使用了一个信用卡记账示例应用,这个应用实现了两个 Widget:

  • RecentPurchases: 显示某个信用卡账户最近的购买记录
  • DueDate: 显示某个信用卡账户消费额 & 还款日期

Tips:

Apple 并没有放出该 session 中演示的 demo 的源码,但是,另一 Widgets Code-along 系列 session 中,所演示的 Emoji Rangers demo 提供了源码,同时也实现了本文所描述的配置能力,可以用作参考。

Widget 的可配置的参数列表是使用 Intents 进行配置的。Intents 是 Apple 在 WWDC 2016 引入的新概念,了解 SiriKit 的开发者对此肯定不会感到陌生(参见 Introducing SiriKitIntroduction to Siri Shortcuts)。

为了让用户可以自定义 RecentPurchases Widget 所显示的信用卡账户、对应的消费分类的功能,我们可以定义一个包含了两个参数的 Intent:

  • Card:Widget 所显示消费记录对应的信用卡账户
  • Category:Widget 所显示消费记录的特定分类

基于我们定义的这个 Intent,WidgetKit 会自动为我们生成如下图所示的配置界面,其中 Card 和 Category 参数分别对应一个配置行。

在用户进行 Widget 配置时,WidgetKit 可以通过 Intent Handling Protocol 从我们的 Widget ExtensionHost App 获取要显示的待选项列表(这一点在后面会详细讲到)。

最后,在获取 Widget Timeline 数据时,WidgetKit 会将用户所自定义的 Intent 实例传入我们的 Widget Extension,我们可以使用该 Intent 实例中的信息来返回个性化的 Timeline 数据。

Widget 支持配置的参数类型

Widget 支持配置从整型、字符串等基础类型到日期、URL 等高级类型的参数,同时支持自定义参数类型 & 自定义枚举类型。

所有支持的类型配置可见下图:

支持自定义输入模式

其中,特定的类型还有近一步的自定义选项来定制输入 UI。例如,Decimal 类型可以选择采用输入框(Number Field)输入或者是滑块(Slider)输入,同时可以定制输入的上下限;Duration 类型可以定制输入值的单位为或者;Date Components 可以指定输入日期还是时间,指定日期的格式等等。

支持自定义参数类型

除了系统自带的参数类型以外,也支持自定义参数类型。可以通过 Add Type... 添加自定义的参数类型,通过Add Enum... 添加自定义的枚举类型,Xcode 会自动生成/更新对应的 Swift 类型(在 Xcode 12 beta 中添加自定义类型后,大部分情况下需要重新 build 项目,或者重启 Xcode 才能看到生成的 Swift 类型😅)。

可能有读者会注意到,上图中显示的第二个自定义枚举类型 Dynamic,支持动态生成所显示的待选项列表,这个我们会在后面详细介绍。

支持输入多个值

大部分类型的参数支持输入多个值,即输入一个数组。同时,支持根据不同的 Widget 大小,限制数组的固定长度。

为 Widget 添加个性化配置能力

下面,基于前述的信用卡实例应用中的 RecentPurchases Widget,对如何为 Widget 添加个性化配置的能力做逐步、详细的介绍。

确定 Widget 可配置的选项

RecentPurchases Widget 目前一次只能显示一张卡片的消费记录等信息,所以很自然,我们会想要让这个 Widget 支持自定义要显示的信用卡账号。同时,多个消费记录可能属于不同的类别(category),那么很自然的,我们可以让用户选择只显示某一个类别的消费记录。

所以,我们希望RecentPurchases Widget 可以支持自定义信用卡账号(card)以及消费类别(category)两个参数。

在 Xcode 中自定义 Intent 类型

首先,我们在工程中的一个 Intent 定义文件中 (如项目中没有已有文件,可以通过 Choose File > New > File 选择 SiriKit Intent Definition File 添加)中,定义一个新的 Intent,叫做 ViewRecentPurchasesIntent

需要注意以下几点:

  • Intent 的 Category 选择为 View(即用于展示/配置 UI)

  • 选中 Intent is eligible for widgets

  • 取消选中 Siri can ask value for run(除非该 Intent 也用于 Siri Shortcuts)

在定义完新的 Intent 类型后,Xcode 会自动生成对应的 Swift 类型文件(以及相对应的 IntentHandling 协议,见下),我们在 Widget Extension & Host App 均可以使用这个 Intent 类型。(Xcode 12 beta 中添加新的 Intent 类型后可能需要重新 Build target,或者重启 Xcode 才能看到/使用新的类型)

实现 IntentHandling 协议

在示例应用中的 card 参数,用户添加了那些信用卡账号只有运行时才知道,对于那些需要在运行时确定有哪些待选项的参数,我们可以选中 Options are provided dynamically 选项,并实现对应的 IntentHandling 协议。

一般我们通过创建一个 Intent Extension target 来处理和系统 Intents 相关的交互。

关于什么是 Intent Handling,如何提供某个 Intent 的 Handler 实现可以参考 SiriKit Programming Guide 中的 Siri Intents 部分内容。

以之前定义的 ViewRecentPurchasesIntent 为例,Xcode 会自动生成一个 ViewRecentPurchasesIntentHandling 协议。通过指定一个 Handler 类,并实现下面两个方法:

  • provideCardOptionsCollection(for:with:)
    在用户点击 Widget 中 Card 配置项的时候,WidgetKit 会展示上图右侧中的列表 UI,其中的数据由这个方法异步返回。

  • defaultCard(for:)
    我们可以通过实现该方法,在用户首次添加我们的 Widget 时,对于该 Widget 的某一个可配置项返回一个默认的参数值。例如在图示的实现中,我们返回了用户的主要信用卡(Primary Card)。

Tips:

top Created with Sketch.