WidgetKit — 苹果框架,在 iOS 14 中推出,允许开发者在 iPhone 和 iPad 的主屏幕、Mac 桌面和 Apple Watch 表盘上放置动态小组件。小组件无需打开应用程序即可显示关键信息 — 天气预报、货币汇率、日历、步数。根据 Apple Developer Documentation, 2026,WidgetKit 每天在苹果生态系统中处理多达 20 亿次小组件更新,使其成为在系统屏幕上显示信息最常用的框架之一。
要点
WidgetKit — 苹果框架,用于创建在苹果设备系统屏幕上显示内容的小组件。小组件是应用程序的微型表示,用户可以在“抖动”模式(jiggle mode)下将其放置在主屏幕上。与 WidgetKit 之前存在的 watchOS complications 不同,新框架通过 SwiftUI 上的统一 API 统一了所有苹果平台的小组件创建。
WidgetKit 的工作原理基于 TimelineProvider — 一个创建有序 TimelineEntry 数组的对象,其中每个条目包含一个 Snapshot(小组件在特定时间的具体状态)。系统按顺序显示条目,在时间轴上过渡到下一个条目时更新小组件。在条目之间,WidgetKit 不会调用应用程序代码 — 处理器时间仅在创建新的 Timeline 时消耗。
根据 WWDC 2024 Session “WidgetKit:What’s new” 的数据,平均 iOS 用户主屏幕上有 8–12 个小组件,最受欢迎的类别是天气、时间、日历、健身和金融。WidgetKit 在日常使用中每天消耗不到 1% 的电量,因为更新是按计划进行的,而不是实时的。
在 iOS 14 之前,小组件仅以 Today View 的形式存在 — 从第一个屏幕向左滑动即可访问的面板。Today Extension 有严重的限制:它们仅在“今天”屏幕上可用,需要打开应用程序才能更新内容,并且对尺寸的支持有限。WidgetKit 完全取代了 Today Extension,在主屏幕、锁屏(iOS 16+)和 Mac 桌面上提供小组件。
WidgetKit 架构基于三个关键协议:TimelineProvider、TimelineEntry 和 Widget。TimelineEntry 是一个数据模型,表示小组件在特定时间的状态。TimelineProvider 创建此类条目的数组(Timeline),为每个条目指定激活日期。Widget — 将提供者与 SwiftUI 视图连接的入口点。
getTimeline 方法在首次添加小组件时由系统调用,然后定期调用 — 通常每 1–6 小时一次,具体取决于提供者类型。Timeline 可以包含未来数小时或数天的条目,使小组件能够在更新之间无需调用应用程序代码即可工作。如果需要紧急更新小组件(例如,汇率发生变化),应用程序可以强制调用 WidgetCenter.shared.reloadAllTimelines()。
struct SimpleEntry: TimelineEntry {
let date: Date
let value: Double
}
struct Provider: TimelineProvider {
typealias Entry = SimpleEntry
func placeholder(in context: Context) -> Entry {
Entry(date: Date(), value: 0)
}
func getSnapshot(
in context: Context,
completion: @escaping (Entry) -> Void
) {
Entry(date: Date(), value: 42.5)
}
func getTimeline(
in context: Context,
completion: @escaping (Timeline<Entry>, Error?) -> Void
) {
let entry = Entry(date: Date(), value: fetchLatestValue())
let nextUpdate = Calendar.current
.date(byAdding: .hour, value: 1, to: Date())!
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
completion(timeline, nil)
}
}
WidgetKit 支持三种小组件尺寸,每种都有固定的比例。Small(iPhone 上 170×170 pt)显示紧凑的信息 — 一个值、图标或短文本。Medium(364×170 pt)宽度是 small 的两倍,适合显示几个值或迷你图表。Large(364×382 pt)垂直占据近半个屏幕,允许显示表格、列表或扩展数据。
开发者必须支持至少两种尺寸 — Apple 推荐 small + medium。Large 小组件仅在应用程序有足够内容填充如此大的体积时才需要。每种尺寸都有自己的 SwiftUI 视图,WidgetKit 在系统屏幕上渲染该视图。重要的是,WidgetKit 不支持自定义尺寸 — 只有三种固定尺寸,这保证了界面的一致性。
struct WeatherWidget: Widget {
let kind: String = "WeatherWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
WeatherWidgetView(entry: entry)
}
.configurationDisplayName("Weather")
.description("Current temperature and forecast")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
WidgetKit 提供两种配置类型 — StaticConfiguration 和 IntentConfiguration。StaticConfiguration 适用于向所有用户显示相同内容的小组件:货币汇率、天气、日历。IntentConfiguration 允许用户在添加小组件时通过 Siri 意图系统进行自定义 — 例如,为天气选择特定城市或为股票价格选择特定代码。
IntentConfiguration 使用 INWidgetIntent — 来自 SiriKit 的 INIntent 的子类。当用户添加小组件并选择参数(例如城市)时,系统会保存此意图,并在每次更新时将其传递给 TimelineProvider。提供者在 getTimeline 方法中接收意图,并使用其参数生成内容。IntentConfiguration 是个性化小组件的首选方法,因为它与 Siri 和 Shortcuts 集成。
struct WeatherWidgetEntryView: View {
var entry: WeatherEntry
var body: some View {
VStack(alignment: .leading) {
Text(entry.cityName)
.font(.caption)
.foregroundColor(.secondary)
Text("\(entry.temperature)°C")
.font(.largeTitle)
}
}
}
struct WeatherWidget: Widget {
var body: some WidgetConfiguration {
IntentConfiguration(
kind: "WeatherWidget",
intent: WeatherConfigIntent.self,
provider: WeatherTimelineProvider()
) { entry in
WeatherWidgetEntryView(entry: entry)
}
}
}
创建小组件始于在 Xcode 中添加 Widget Extension Target:File → New → Target → Widget Extension。Xcode 自动生成包含 TimelineEntry、TimelineProvider 和 WidgetConfiguration 的结构。开发者只需实现用于显示数据的 SwiftUI 视图并为正确的更新计划配置提供者。
下面 — 一个用于显示当前比特币价格的简单小组件的完整示例:Provider 通过 URLSession 加载价格并创建每小时更新的 Timeline。WidgetSwiftUIView 用大字体显示价格,用小字体显示最后更新时间。
struct BTCPriceEntry: TimelineEntry {
let date: Date
let price: Double
let change24h: Double
}
struct BTCWidgetEntryView: View {
var entry: BTCPriceEntry
var body: some View {
VStack {
Text("BTC/USD").font(.caption)
Text("$\(entry.price, specifier: "%.0f")")
.font(.title2).fontWeight(.bold)
Text(entry.change24h > 0 ? "+" : "")
}
}
}
从 iOS 16 开始,WidgetKit 扩展了对 Lock Screen — iPhone 锁屏的支持。锁屏小组件有两种类型:inline(时钟下方的一行文本)和 rectangular(矩形区域)。与主屏幕小组件不同,锁屏小组件更新更频繁 — 系统触发器允许每 15–30 分钟更新一次,以便在不解锁手机的情况下显示最新信息。
锁屏小组件需要通过 WidgetConfiguration 单独配置,使用 accessoryFamilies:accessoryCircular、accessoryRectangular、accessoryInline。这些系列在尺寸和内容上有严格的限制 — 它们不支持图片、动画和自定义字体。Apple 建议仅对锁屏小组件使用文本信息和系统图标 SF Symbols。
在开发小组件时,重要的是要考虑 WidgetKit 的限制。小组件是只读视图:它们不处理触摸事件(除了打开应用程序的点击)。小组件不支持动画、视频、键盘输入、滚动或交互式元素。每个小组件是数据在特定时间的静态快照,尝试添加交互性将导致应用程序在 App Store 中被拒绝。
最佳实践包括使用 Widget Center 进行强制更新、在 TimelineProvider 级别缓存数据以获得快速响应、以及使用占位符显示初始状态。同样重要的是支持多种尺寸 — 用户期望小组件在 small 和 medium 变体中都可用。严格避免显示不准确或过时的数据 — 用户会长时间记住来自小组件的错误信息。
| 不能做什么 | 为什么 |
|---|---|
| 动画和视频 | 小组件是静态快照;动画消耗电池 |
| 交互性 | WidgetKit 不支持除应用程序链接之外的 UI 元素 |
| 滚动 | 固定尺寸,无滚动 |
| 键盘 | 在小组件中输入文本是不可能的 |
| 实时数据 | 数据根据 Timeline 计划更新,而非实时 |
| 自定义尺寸 | 仅 small、medium、large、accessory* 固定 |
常见问题
可以,WidgetKit 是跨平台的。同一个 Widget Extension 可以用统一的 SwiftUI 代码包含在 iOS、iPadOS 和 macOS 目标中。差异仅体现在支持的 Family 上 — Mac 上没有 accessoryRectangular。
根据 Timeline 计划。开发者确定下一次更新的时间 — 在一分钟后或一天后。系统还可以为经常使用的小组件加速更新。
不能,WidgetKit 不支持 UIButton 或任何交互式元素。唯一的操作是点击小组件,通过 deep link 打开应用程序。
使用 WidgetCenter.shared.reloadAllTimelines() 或针对特定小组件使用 reloadTimelines(ofKind:)。从应用程序调用会立即向提供者请求新的 Timeline。
影响极小 — 日常使用中每天 不到 1% 的电量。WidgetKit 限制后台更新,不会让应用程序保持活跃。主要消耗是首次添加时的 Timeline 创建。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。