小组件是什么

iOS 小组件是放在桌面、锁屏上的小卡片,用 WidgetKit 写,用 SwiftUI 画。它不常驻运行,按系统调度定时刷新,用来展示一眼能看完的信息。

小组件是给用户看一眼的小窗口,不是缩小版 App。

这篇把一个最简单的小组件跑起来。

小组件和主 App 是两个进程,不能直接共享内存。它们之间靠 App Group 共享容器传数据:主 App 写一份文件或 UserDefaults,小组件读这份。这也是为什么小组件总是"数据稍微慢半拍"——它等主 App 通知刷新才去读最新值。设计时要接受这一点,把小组件当成"展示当前状态"的窗口,而不是实时交互的控制台。

新建 Widget Target

在 Xcode 里 New Target,选 Widget Extension,它会生成一个独立 target,跟主 App 共享一份代码。

Widget 速查
  • TimelineProvider告诉系统画什么。
  • WidgetEntryViewSwiftUI 画卡片。
  • family指定小/中/大尺寸。

同一组尺寸可以共用一个视图,用 @Environment 拿尺寸做适配。深色模式靠系统自动切换,别自己写两套颜色。文字别用太小的,桌面一眼要看清,图标也是。

写视图与时间线

struct Provider: TimelineProvider {
  func snapshot(in context: Context) async -> Entry { Entry(date: .now, temp: 26) }
  func timeline(in context: Context) async -> Timeline<Entry> {
    Timeline(entries: [Entry(date: .now, temp: 26)], policy: .after(.now.addingTimeInterval(1800)))
  }
}

Timeline 的 policy 决定系统下次什么时候再来问你。.after 是定时刷新,.atEnd 是到时间线末尾再问一次。频率不能太频繁——系统对一天刷新多少次有上限,把不重要的更新攒一攒,一次刷完。

数据怎么更新

小组件自己不能一直跑。主 App 拉到新数据后存进共享容器,再告诉系统刷新小组件。系统按 policy 决定下次刷新时间。

主动刷新用 WidgetCenter.shared.reloadAllTimelines(),告诉系统"我数据变了,重画一次"。但别一有变化就调,系统会节流;把刷新合并到真正有意义的时刻,比如用户在主 App 做完一次操作之后。

苹果小组件:桌面背景上悬浮多个不同尺寸的发光小组件方块卡片、卡片上是占位图形与进度环的蓝调插画
多个尺寸不一的发光小组件悬浮在桌面背景上。