Highlight
Widget code-along 第三集演示了在 widget extension 内处理 URLSession、用 SwiftUI
Link跳转到 App 内容、用WidgetBundle暴露多个 widget,并通过 Intent Extension 为配置提供动态选项。
核心内容
第三集从一个已经有基础 timeline 的项目继续。新的 Leaderboard widget 会把角色按 health 排序展示。问题随之出现:widget 需要取数据,需要让每一行跳到 App 内的角色详情,还要和原来的 Ranger Detail widget 一起出现在 widget gallery。
这几个需求都卡在 widget extension 的边界上。网络请求不能假设由宿主 App 接管;可点击区域要落在 widget 的 SwiftUI 视图里;同一个 extension 里还只能有一个 @main。如果直接把 App 里的写法搬进来,开发者会很快碰到这些边界。
Apple 在这场 code-along 里把边界逐个拆开:timeline provider 用 completion handler 支持异步请求;widget 自己响应它创建的 URLSession,包括 background session;SwiftUI Link 可以把一行 widget 内容变成深链接入口;WidgetBundle 负责把多个 widget 放进同一个 extension;Intent Extension 则把原来写死的配置列表换成动态选项。
最后的结果是一个更接近真实 App 的 widget。它能取数据,能跳转到指定内容,能在一个 extension 里提供多个入口,还能让配置列表跟随远端数据变化。
详细内容
1. 在 widget extension 里取数据
(01:28)Leaderboard widget 的数据来自 CharacterDetail 上的 loadLeaderboardData 异步请求。Transcript 明确说明,timeline provider API 使用 completion handler,目的就是让 network fetch 这类异步任务容易接入。
本 session 没有公开 Code tab snippet。下面只保留 transcript 中出现的调用形态,不补全业务实现。
CharacterDetail.loadLeaderboardData
URLSession
data task
关键点:
loadLeaderboardData是 Leaderboard 数据的异步入口。- timeline provider 依靠 completion handler 等待异步任务完成。
- session 中演示的是普通 in-process URL session。
- 这个请求用本地文件模拟远端 fetch;实际项目里通常会调用 remote Web service。
(02:20)background session 在 widget 里有一个特殊点:它完成时不会启动 extension 的 hosting app。Widget 会响应自己创建的所有 URLSession,包括 background session。
onBackgroundURLSessionEvents
sessionIdentifier
completion block
关键点:
onBackgroundURLSessionEvents是 widget configuration 上的 modifier。- 它对应 App 里常见的 application delegate 回调职责。
- 系统提供
sessionIdentifier和 completion block。 - transcript 只说明管理方式与 App 中相同,没有展开具体队列或持久化策略。
2. 用 SwiftUI Link 做 widget 内跳转
(03:20)Leaderboard 里每一行都是 AllCharactersView 里的一个 HStack。目标是点击某个角色时,直接打开该角色的信息页面。
Link(destination: character.url) {
HStack {
...
}
}
关键点:
Link是 session 中点名的新 SwiftUI API。destination使用角色自己的 URL。- 原来的
HStack仍然承载这一行的内容。 - 点击 widget 行时,系统会高亮该行,然后打开对应角色详情。
3. 用 WidgetBundle 暴露多个 widget
(04:36)项目里有 Leaderboard widget 和 Ranger Detail widget,但一个 process 里只能有一个 @main。解决办法是把 @main 从单个 widget 移到 bundle 上。
@main -> WidgetBundle
WidgetBundle -> Leaderboard widget
WidgetBundle -> Ranger Detail widget
关键点:
WidgetBundle用来在同一个 extension 里声明多个 widget。@main放在 bundle 上,而不是分别放在两个 widget 上。- session 中演示的结果是 widget gallery 同时出现 Leaderboard widget 和 Ranger Detail widget。
- 这个结构适合一个 App 提供多个信息入口。
4. 用 Intent Extension 提供动态配置选项
(05:31)上一集已经有可配置 widget,但选项列表是硬编码的。第三集把 SiriKit intent 的参数类型改成 custom type,再由 Intent Extension 提供动态列表。
IntentHandler
identifier
displayString
CharacterDetail.remoteCharacters
Intent identifier -> characterFromName
关键点:
- custom intent type 默认带有
identifier和displayString两个属性。 - 这些值来自
IntentHandler。 - 选项提供过程也是异步调用,和 timeline 方法类似。
- session 中把
CharacterDetail.remoteCharacters加入选项列表,用来模拟从网络取得更多角色。 - widget 读取用户选择时,用 intent identifier 找回对应角色。
(08:01)配置界面最终出现了原始选项 Power Panda、Egghead、Spouty,也出现了远端选项 Mr. Spook、Cake、Octo。用户选择 Mr. Spook 后,Home Screen 上的 widget 展示这个角色。
核心启发
1. 做一个远端排行榜 widget
- 做什么:把服务端排行榜放到 Home Screen,按最新分数或状态排序。
- 为什么值得做:session 明确演示了 Leaderboard widget 通过异步请求获取角色列表。
- 怎么开始:先把 timeline provider 接到现有 fetch 方法;如果请求可能在后台完成,再在 widget configuration 上接入
onBackgroundURLSessionEvents。
2. 做一个可点击的列表 widget
- 做什么:让 widget 的每一行打开 App 内对应详情页。
- 为什么值得做:session 演示了把
HStack包进 SwiftUILink,并把 destination 指向角色 URL。 - 怎么开始:为列表里的每个实体准备 URL,在 widget row 外层使用
Link(destination:)。
3. 用一个 extension 提供多个 widget
- 做什么:同时提供总览型 widget 和详情型 widget。
- 为什么值得做:session 演示了 Leaderboard widget 与 Ranger Detail widget 通过
WidgetBundle同时进入 widget gallery。 - 怎么开始:把
@main移到WidgetBundle,在 bundle body 里列出多个 widget。
4. 做服务端驱动的 widget 配置
- 做什么:让用户配置 widget 时看到最新项目、设备、角色或关注对象。
- 为什么值得做:session 通过 Intent Extension 把硬编码列表扩展为动态选项。
- 怎么开始:把 intent 参数改成 custom type,在
IntentHandler中返回带有identifier和displayString的选项,并在 widget 里通过 identifier 找回实体。
关联 Session
- Widgets Code-along, part 1: The adventure begins — 从创建 widget project、provider 和基础 timeline 开始。
- Widgets Code-along, part 2: Alternate timelines — 继续讲 timeline、system intelligence、多种 widget family 和配置。
- Build SwiftUI views for widgets — 讲如何用 SwiftUI 构建适合 widget 的 glanceable view。
- Add configuration and intelligence to your widgets — 深入 configurable widget、Siri suggestions 和 Smart Stack 相关能力。
- Design great widgets — 从内容、颜色、尺寸、布局和排版角度补齐 widget 设计原则。
评论
GitHub Issues · utterances