WidgetKit — 是什么,小组件框架和 SwiftUI

作者: IT Sectr 发布日期: 2026-06-16 阅读时间: 9 分钟

WidgetKit — 苹果框架,在 iOS 14 中推出,允许开发者在 iPhone 和 iPad 的主屏幕、Mac 桌面和 Apple Watch 表盘上放置动态小组件。小组件无需打开应用程序即可显示关键信息 — 天气预报、货币汇率、日历、步数。根据 Apple Developer Documentation, 2026WidgetKit 每天在苹果生态系统中处理多达 20 亿次小组件更新,使其成为在系统屏幕上显示信息最常用的框架之一。

要点

  • WidgetKit — 用于在 iOS 14+、iPadOS 14+、macOS 11+ 和 watchOS 10+ 上通过 SwiftUI 渲染创建小组件的框架。
  • TimelineProvider — 协议,决定小组件何时以及多久根据 TimelineEntry 更新其内容。
  • WidgetFamily — 三种尺寸(small、medium、large),开发者可以分别配置每种尺寸。
  • WidgetConfiguration — 小组件的入口点,确定配置类型(Static、Intent、AppEntity)和尺寸系列。
  • 限制 — 小组件没有动画,不支持视频、键盘和内部滚动。

什么是 WidgetKit 以及它是如何工作的?

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% 的电量,因为更新是按计划进行的,而不是实时的。

WidgetKit 与旧的 Today Extension 有何不同

在 iOS 14 之前,小组件仅以 Today View 的形式存在 — 从第一个屏幕向左滑动即可访问的面板。Today Extension 有严重的限制:它们仅在“今天”屏幕上可用,需要打开应用程序才能更新内容,并且对尺寸的支持有限。WidgetKit 完全取代了 Today Extension,在主屏幕、锁屏(iOS 16+)和 Mac 桌面上提供小组件。

  • 小组件在主屏幕上,而不仅仅在 Today View 中
  • 通过 TimelineProvider 自主更新,无需打开应用程序
  • 三个预定义尺寸而不是一个
  • Smart Rotate 和 Smart Stack — 系统自动轮换小组件
  • 所有苹果平台的统一 SwiftUI API

WidgetKit 架构:TimelineProvider 和 Entry

WidgetKit 架构基于三个关键协议:TimelineProviderTimelineEntryWidget。TimelineEntry 是一个数据模型,表示小组件在特定时间的状态。TimelineProvider 创建此类条目的数组(Timeline),为每个条目指定激活日期。Widget — 将提供者与 SwiftUI 视图连接的入口点。

getTimeline 方法在首次添加小组件时由系统调用,然后定期调用 — 通常每 1–6 小时一次,具体取决于提供者类型。Timeline 可以包含未来数小时或数天的条目,使小组件能够在更新之间无需调用应用程序代码即可工作。如果需要紧急更新小组件(例如,汇率发生变化),应用程序可以强制调用 WidgetCenter.shared.reloadAllTimelines()。

基本 TimelineProvider

swift
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)
    }
}

Widget Family:small、medium、large

WidgetKit 支持三种小组件尺寸,每种都有固定的比例。Small(iPhone 上 170×170 pt)显示紧凑的信息 — 一个值、图标或短文本。Medium(364×170 pt)宽度是 small 的两倍,适合显示几个值或迷你图表。Large(364×382 pt)垂直占据近半个屏幕,允许显示表格、列表或扩展数据。

开发者必须支持至少两种尺寸 — Apple 推荐 small + medium。Large 小组件仅在应用程序有足够内容填充如此大的体积时才需要。每种尺寸都有自己的 SwiftUI 视图,WidgetKit 在系统屏幕上渲染该视图。重要的是,WidgetKit 不支持自定义尺寸 — 只有三种固定尺寸,这保证了界面的一致性。

通过 WidgetConfiguration 配置尺寸

swift
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])
    }
}

小组件配置类型:Static 和 Intent

WidgetKit 提供两种配置类型 — StaticConfigurationIntentConfiguration。StaticConfiguration 适用于向所有用户显示相同内容的小组件:货币汇率、天气、日历。IntentConfiguration 允许用户在添加小组件时通过 Siri 意图系统进行自定义 — 例如,为天气选择特定城市或为股票价格选择特定代码。

IntentConfiguration 使用 INWidgetIntent — 来自 SiriKit 的 INIntent 的子类。当用户添加小组件并选择参数(例如城市)时,系统会保存此意图,并在每次更新时将其传递给 TimelineProvider。提供者在 getTimeline 方法中接收意图,并使用其参数生成内容。IntentConfiguration 是个性化小组件的首选方法,因为它与 Siri 和 Shortcuts 集成。

带有参数选择的 IntentConfiguration

swift
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)
        }
    }
}

在 SwiftUI 中创建小组件:分步示例

创建小组件始于在 Xcode 中添加 Widget Extension Target:File → New → Target → Widget Extension。Xcode 自动生成包含 TimelineEntry、TimelineProvider 和 WidgetConfiguration 的结构。开发者只需实现用于显示数据的 SwiftUI 视图并为正确的更新计划配置提供者。

下面 — 一个用于显示当前比特币价格的简单小组件的完整示例:Provider 通过 URLSession 加载价格并创建每小时更新的 Timeline。WidgetSwiftUIView 用大字体显示价格,用小字体显示最后更新时间。

swift
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+ 锁屏小组件

从 iOS 16 开始,WidgetKit 扩展了对 Lock Screen — iPhone 锁屏的支持。锁屏小组件有两种类型:inline(时钟下方的一行文本)和 rectangular(矩形区域)。与主屏幕小组件不同,锁屏小组件更新更频繁 — 系统触发器允许每 15–30 分钟更新一次,以便在不解锁手机的情况下显示最新信息。

锁屏小组件需要通过 WidgetConfiguration 单独配置,使用 accessoryFamilies:accessoryCircular、accessoryRectangular、accessoryInline。这些系列在尺寸和内容上有严格的限制 — 它们不支持图片、动画和自定义字体。Apple 建议仅对锁屏小组件使用文本信息和系统图标 SF Symbols。

  • accessoryCircular — 用于时钟下方位置的紧凑圆形小组件
  • accessoryRectangular — 用于时钟上方区域的矩形小组件
  • accessoryInline — 时间下方的单行文本,最小尺寸
  • 限制:仅文本、SF Symbols、渐变;无图片和视频

WidgetKit 的最佳实践和限制

在开发小组件时,重要的是要考虑 WidgetKit 的限制。小组件是只读视图:它们不处理触摸事件(除了打开应用程序的点击)。小组件不支持动画、视频、键盘输入、滚动或交互式元素。每个小组件是数据在特定时间的静态快照,尝试添加交互性将导致应用程序在 App Store 中被拒绝。

最佳实践包括使用 Widget Center 进行强制更新、在 TimelineProvider 级别缓存数据以获得快速响应、以及使用占位符显示初始状态。同样重要的是支持多种尺寸 — 用户期望小组件在 small 和 medium 变体中都可用。严格避免显示不准确或过时的数据 — 用户会长时间记住来自小组件的错误信息。

WidgetKit 限制表

不能做什么为什么
动画和视频小组件是静态快照;动画消耗电池
交互性WidgetKit 不支持除应用程序链接之外的 UI 元素
滚动固定尺寸,无滚动
键盘在小组件中输入文本是不可能的
实时数据数据根据 Timeline 计划更新,而非实时
自定义尺寸仅 small、medium、large、accessory* 固定

常见问题

能否为 iOS 和 macOS 创建一个小组件?

可以,WidgetKit 是跨平台的。同一个 Widget Extension 可以用统一的 SwiftUI 代码包含在 iOS、iPadOS 和 macOS 目标中。差异仅体现在支持的 Family 上 — Mac 上没有 accessoryRectangular。

WidgetKit 多久更新一次小组件?

根据 Timeline 计划。开发者确定下一次更新的时间 — 在一分钟后或一天后。系统还可以为经常使用的小组件加速更新。

能否在小组件中添加按钮?

不能,WidgetKit 不支持 UIButton 或任何交互式元素。唯一的操作是点击小组件,通过 deep link 打开应用程序。

如何从应用程序强制更新小组件?

使用 WidgetCenter.shared.reloadAllTimelines() 或针对特定小组件使用 reloadTimelines(ofKind:)。从应用程序调用会立即向提供者请求新的 Timeline。

小组件会影响电池寿命吗?

影响极小 — 日常使用中每天 不到 1% 的电量。WidgetKit 限制后台更新,不会让应用程序保持活跃。主要消耗是首次添加时的 Timeline 创建。

总结

  • WidgetKit — 苹果框架,适用于 iOS 14+、iPadOS 14+、macOS 11+ 和 watchOS 10+,使用 SwiftUI 显示内容。
  • TimelineProvider 通过 TimelineEntry 数组管理更新计划,每个条目代表小组件在特定时间的状态。
  • Widget Family 包括三种尺寸 — small、medium、large — 以及用于 iOS 16+ 锁屏的 accessory 系列。
  • StaticConfiguration 适用于所有用户相同的内容,IntentConfiguration — 适用于带有设置的个性化小组件。
  • 小组件是静态的 — 没有动画、交互性、滚动和视频;只读数据展示。
  • 锁屏小组件(iOS 16+)是 accessoryCircular、accessoryRectangular 和 accessoryInline,带有内容限制。
  • 强制更新 通过 WidgetCenter.shared.reloadAllTimelines() 允许立即请求新的 Timeline。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读