widgets
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWrite and review SwiftUI WidgetKit code, choosing the right configuration, timeline policy, and surface so the widget renders correctly in every mode, updates within its budget, and behaves correctly across the extension/app process boundary.
Review process:
- Establish the widget execution model (the extension process, app groups, the timeline lifecycle, the reload budget) using .
references/fundamentals.md - Validate the timeline provider (/
placeholder/snapshot, reload policy,timelinereloads, entry relevance) usingWidgetCenter.references/timeline-provider.md - Validate the configuration and any user-configurable parameters (,
StaticConfiguration,AppIntentConfiguration) usingWidgetConfigurationIntent.references/configuration-and-intents.md - Check whether any legacy API is in use and route it to the modern equivalent (SiriKit → App Intents, ClockKit → WidgetKit,
.intentdefinition→PreviewProvider) using#Preview.references/migration-and-deprecations.md - Validate data loading - networking, persistence, images, location - in the provider and intents using .
references/data-and-networking.md - Validate family support and per-family layout (, sizing, content margins,
WidgetFamily) usingViewThatFits.references/families-and-layout.md - Validate Lock Screen / accessory widgets and watch complications (,
widgetLabel, the transparent-container trick, ClockKit migration) usingAccessoryWidgetBackground.references/lock-screen-and-watch.md - Validate rendering across full-color, accented, tinted, and vibrant modes (,
widgetRenderingMode,widgetAccentable, the luminance-to-alpha trick) usingwidgetAccentedRenderingMode.references/rendering-modes-and-tinting.md - Validate interactivity (,
Button(intent:), the app-process boundary,Toggle(intent:),reloadTimelines) usinginvalidatableContent.references/interactive-widgets.md - Validate deep links and navigation into the app (,
widgetURL,Link,onOpenURL) usingOpenIntent.references/deep-linking-and-navigation.md - Validate animations and entry transitions (,
contentTransition+ identity,.transition, what doesn't animate) usinginvalidatableContent.references/animations-and-transitions.md - Validate Control Center controls (, toggle vs button,
ControlWidget, value providers,SetValueIntentreloads) usingControlCenter.references/controls.md - Validate Live Activities and the Dynamic Island (,
ActivityAttributes,ActivityConfiguration, request/update/end, push,DynamicIsland) usingsupplementalActivityFamilies.references/live-activities.md - Validate Smart Stack relevance (,
TimelineEntryRelevance/relevance(),WidgetRelevance, push-based relevance) usingRelevanceConfiguration.references/relevance-and-smart-stacks.md - Check the design and gallery presentation (glanceability, sizes, the don'ts, /
configurationDisplayName, the placeholder) usingdescription.references/design-and-gallery.md - Validate previews and the testing/debugging workflow (, WidgetKit developer mode, the reload budget) using
#Preview(as:).references/previews-and-testing.md - Validate platform-specific surfaces (visionOS spatial widgets, CarPlay, macOS menu bar, the availability map) using .
references/platforms.md - Catch common mistakes using .
references/anti-patterns.md
If doing partial work, load only the relevant reference files.
编写和审查SwiftUI WidgetKit代码,选择合适的配置、时间线策略和界面场景,确保组件在所有模式下渲染正常、在预算内更新,并在扩展/应用进程边界间表现合规。
审查流程:
- 借助确立组件执行模型(扩展进程、应用组、时间线生命周期、重载预算)。
references/fundamentals.md - 借助验证时间线提供者(
references/timeline-provider.md/placeholder/snapshot、重载策略、timeline重载、条目相关性)。WidgetCenter - 借助验证配置及任何用户可配置参数(
references/configuration-and-intents.md、StaticConfiguration、AppIntentConfiguration)。WidgetConfigurationIntent - 检查是否使用了旧版API,并将其替换为现代等效方案(SiriKit → App Intents、ClockKit → WidgetKit、
.intentdefinition→PreviewProvider),参考#Preview。references/migration-and-deprecations.md - 借助验证提供者和意图中的数据加载——网络请求、持久化、图片、位置信息。
references/data-and-networking.md - 借助验证组件家族支持及按家族布局(
references/families-and-layout.md、尺寸、内容边距、WidgetFamily)。ViewThatFits - 借助验证锁屏/附属组件和手表复杂功能(
references/lock-screen-and-watch.md、widgetLabel、透明容器技巧、ClockKit迁移)。AccessoryWidgetBackground - 借助验证全彩、强调、着色、活力模式下的渲染(
references/rendering-modes-and-tinting.md、widgetRenderingMode、widgetAccentable、亮度转透明度技巧)。widgetAccentedRenderingMode - 借助验证交互性(
references/interactive-widgets.md、Button(intent:)、应用进程边界、Toggle(intent:)、reloadTimelines)。invalidatableContent - 借助验证深度链接和应用内导航(
references/deep-linking-and-navigation.md、widgetURL、Link、onOpenURL)。OpenIntent - 借助验证动画和条目过渡(
references/animations-and-transitions.md、contentTransition+ identity、.transition、不支持动画的内容)。invalidatableContent - 借助验证控制中心控件(
references/controls.md、切换器与按钮、ControlWidget、值提供者、SetValueIntent重载)。ControlCenter - 借助验证Live Activities与灵动岛(
references/live-activities.md、ActivityAttributes、ActivityConfiguration、请求/更新/结束、推送、DynamicIsland)。supplementalActivityFamilies - 借助验证智能堆栈相关性(
references/relevance-and-smart-stacks.md、TimelineEntryRelevance/relevance()、WidgetRelevance、基于推送的相关性)。RelevanceConfiguration - 借助检查设计和组件库展示(易读性、尺寸、禁忌、
references/design-and-gallery.md/configurationDisplayName、占位符)。description - 借助验证预览和测试/调试工作流(
references/previews-and-testing.md、WidgetKit开发者模式、重载预算)。#Preview(as:) - 借助验证平台特定界面(visionOS空间组件、CarPlay、macOS菜单栏、可用性映射)。
references/platforms.md - 借助排查常见错误。
references/anti-patterns.md
如果只做部分工作,仅加载相关参考文件。
Task-based routing
基于任务的路由
Match the user's goal to the read order. Load only what you need.
将用户目标与阅读顺序匹配,仅加载所需内容。
"Create my first widget" / "show me a complete widget"
"创建我的第一个组件" / "展示完整的组件示例"
- - the extension, the widget bundle, the timeline lifecycle
references/fundamentals.md - - one widget built end to end (entry → provider → layout → links → tinting → animation → preview)
references/worked-example.md - -
references/timeline-provider.md, entries, reload policyTimelineProvider - - pick families, per-family layout
references/families-and-layout.md - -
references/previews-and-testing.mdto iterate#Preview(as:)
- - 扩展、组件包、时间线生命周期
references/fundamentals.md - - 端到端构建一个组件(条目 → 提供者 → 布局 → 链接 → 着色 → 动画 → 预览)
references/worked-example.md - -
references/timeline-provider.md、条目、重载策略TimelineProvider - - 选择组件家族、按家族布局
references/families-and-layout.md - - 使用
references/previews-and-testing.md迭代开发#Preview(as:)
"Let the user configure my widget"
"允许用户配置我的组件"
- -
references/configuration-and-intents.md+AppIntentConfiguration, dynamic options, defaultsWidgetConfigurationIntent - -
references/timeline-provider.md(the intent is the first argument)AppIntentTimelineProvider
- -
references/configuration-and-intents.md+AppIntentConfiguration、动态选项、默认值WidgetConfigurationIntent - -
references/timeline-provider.md(意图作为第一个参数)AppIntentTimelineProvider
"Add a Lock Screen widget / watch complication"
"添加锁屏组件 / 手表复杂功能"
- - accessory families,
references/lock-screen-and-watch.md,widgetLabel, gauges, ClockKit migrationAccessoryWidgetBackground - - accessory widgets are always rendered in a tint mode
references/rendering-modes-and-tinting.md
- - 附属组件家族、
references/lock-screen-and-watch.md、widgetLabel、仪表盘、ClockKit迁移AccessoryWidgetBackground - - 附属组件始终以着色模式渲染
references/rendering-modes-and-tinting.md
"My widget looks wrong in tinted / dark / accented mode"
"我的组件在着色/深色/强调模式下显示异常"
- -
references/rendering-modes-and-tinting.md,widgetRenderingMode,widgetAccentable, the luminance-to-alpha trick, designing for the accent groupwidgetAccentedRenderingMode - - the transparent
references/lock-screen-and-watch.mdfor accessory widgetscontainerBackground
- -
references/rendering-modes-and-tinting.md、widgetRenderingMode、widgetAccentable、亮度转透明度技巧、为强调组设计widgetAccentedRenderingMode - - 附属组件的透明
references/lock-screen-and-watch.mdcontainerBackground
"Add a button / toggle inside my widget"
"在组件内添加按钮 / 切换器"
- -
references/interactive-widgets.md/Button(intent:), the app-process boundary, App Group store,Toggle(intent:),reloadTimelinesinvalidatableContent - -
references/configuration-and-intents.mdon helper intentsisDiscoverable = false
- -
references/interactive-widgets.md/Button(intent:), 应用进程边界、App Group存储、Toggle(intent:)、reloadTimelinesinvalidatableContent - - 辅助意图设置
references/configuration-and-intents.mdisDiscoverable = false
"Add a Control Center control / Action button / Lock Screen control"
"添加控制中心控件 / 操作按钮 / 锁屏控件"
- -
references/controls.md,ControlWidget(ControlWidgetToggle) vsSetValueIntent(ControlWidgetButton), value providers,AppIntentControlCenter.shared.reloadControls - - the same app-process / shared-store rules apply
references/interactive-widgets.md
- -
references/controls.md、ControlWidget(ControlWidgetToggle)与SetValueIntent(ControlWidgetButton)、值提供者、AppIntentControlCenter.shared.reloadControls - - 同样适用应用进程/共享存储规则
references/interactive-widgets.md
"Build a Live Activity / Dynamic Island"
"构建Live Activity / 灵动岛"
- -
references/live-activities.md/ActivityAttributes,ContentState,ActivityConfigurationregions, request/update/end, staleness, push,DynamicIsland, the iOS-27 landscape Dynamic IslandsupplementalActivityFamilies - -
references/interactive-widgets.mdbuttonsLiveActivityIntent
- -
references/live-activities.md/ActivityAttributes、ContentState、ActivityConfiguration区域、请求/更新/结束、过期、推送、DynamicIsland、iOS 27横屏灵动岛supplementalActivityFamilies - -
references/interactive-widgets.md按钮LiveActivityIntent
"Keep my widget fresh from the server"
"通过服务器保持组件内容新鲜"
- - reload policy, the reload budget, reload on app background
references/timeline-provider.md - - push-updated widgets (
references/relevance-and-smart-stacks.md, iOS 26), and when a Live Activity is the right tool insteadWidgetPushHandler
- - 重载策略、重载预算、应用后台时重载
references/timeline-provider.md - - 推送更新组件(
references/relevance-and-smart-stacks.md, iOS 26),以及何时适合使用Live Activity替代WidgetPushHandler
"Make my widget show up in the Smart Stack at the right time"
"让我的组件在合适的时间出现在智能堆栈中"
- -
references/relevance-and-smart-stacks.md,TimelineEntryRelevance+relevance(),WidgetRelevance(watchOS 26),RelevanceConfigurationRelevantContext
- -
references/relevance-and-smart-stacks.md、TimelineEntryRelevance+relevance()、WidgetRelevance(watchOS 26)、RelevanceConfigurationRelevantContext
"Fetch data / load images / use a database or location in my widget"
"在组件中获取数据 / 加载图片 / 使用数据库或位置信息"
- - App Group snapshot,
references/data-and-networking.mdfetch in the provider, image downsampling, SwiftData/Core Data,asyncNSWidgetUsesLocation - - where fetching fits in the lifecycle and the budget
references/timeline-provider.md
- - App Group快照、提供者中的
references/data-and-networking.md获取、图片降采样、SwiftData/Core Data、asyncNSWidgetUsesLocation - - 数据获取在生命周期和预算中的位置
references/timeline-provider.md
"Deep link / open my app from the widget"
"从组件深度链接 / 打开我的应用"
- -
references/deep-linking-and-navigation.mdvswidgetURL, per-family rules,Link,onOpenURLOpenIntent
- -
references/deep-linking-and-navigation.md与widgetURL对比、按家族规则、Link、onOpenURLOpenIntent
"Animate my widget / make values roll or transition"
"为组件添加动画 / 实现数值滚动或过渡"
- - entry diffing,
references/animations-and-transitions.md,contentTransition(.numericText)+.transition,.id, what doesn't animateinvalidatableContent
- - 条目差异、
references/animations-and-transitions.md、contentTransition(.numericText)+.transition、.id、不支持动画的内容invalidatableContent
"Modernize an old widget / I'm seeing IntentConfiguration / ClockKit / PreviewProvider"
"现代化旧组件 / 我看到了IntentConfiguration / ClockKit / PreviewProvider"
- - the old → new map,
references/migration-and-deprecations.md, the ClockKit migrator, dual-pathCustomIntentMigratedAppIntent#available
- - 新旧映射、
references/migration-and-deprecations.md、ClockKit迁移器、双路径CustomIntentMigratedAppIntent#available
"Design my widget well / make it gallery-ready"
"优化组件设计 / 使其符合组件库要求"
- - glanceable/personal/relevant, sizes & tap styles, the don'ts, the snapshot, the placeholder
references/design-and-gallery.md
- - 易读/个性化/相关性、尺寸与点击样式、禁忌、快照、占位符
references/design-and-gallery.md
"Support visionOS / CarPlay / macOS / Apple Watch"
"支持visionOS / CarPlay / macOS / Apple Watch"
- - spatial widgets (
references/platforms.md,supportedMountingStyles,widgetTexture), CarPlay, macOS menu bar, the availability maplevelOfDetail
- - 空间组件(
references/platforms.md、supportedMountingStyles、widgetTexture)、CarPlay、macOS菜单栏、可用性映射levelOfDetail
"My widget won't update / shows stale data / never appears"
"我的组件无法更新 / 显示过期数据 / 始终不出现"
- - the reload budget, WidgetKit developer mode, debugging
references/previews-and-testing.md - - the usual causes
references/anti-patterns.md
- - 重载预算、WidgetKit开发者模式、调试
references/previews-and-testing.md - - 常见原因
references/anti-patterns.md
"I'm hitting build errors or rendering bugs"
"我遇到了构建错误或渲染bug"
- - catches with before/after fixes
references/anti-patterns.md
- - 提供前后修复对比
references/anti-patterns.md
Decision trees
决策树
Quick orientation when you know the task but not the right API.
当你知道任务但不确定正确API时的快速指南。
Which configuration should the widget use?
组件应使用哪种配置?
No user configuration, fixed behavior?
-> StaticConfiguration(kind:provider:)
User picks parameters (account, city, repo)?
-> AppIntentConfiguration(kind:intent:provider:) + WidgetConfigurationIntent (iOS 17+)
Migrating an existing iOS 14-16 configurable widget?
-> WidgetConfigurationIntent + CustomIntentMigratedAppIntent (keep intentClassName)
-> or keep IntentConfiguration(kind:intent:provider:) with the legacy INIntent
Appears in the Smart Stack only when relevant (watchOS)?
-> RelevanceConfiguration(kind:provider:) (watchOS 26+)无需用户配置,行为固定?
-> StaticConfiguration(kind:provider:)
用户选择参数(账户、城市、仓库)?
-> AppIntentConfiguration(kind:intent:provider:) + WidgetConfigurationIntent (iOS 17+)
迁移现有iOS 14-16可配置组件?
-> WidgetConfigurationIntent + CustomIntentMigratedAppIntent(保留intentClassName)
-> 或继续使用IntentConfiguration(kind:intent:provider:)搭配旧版INIntent
仅在相关时出现在智能堆栈中(watchOS)?
-> RelevanceConfiguration(kind:provider:) (watchOS 26+)Which timeline provider?
使用哪种时间线提供者?
StaticConfiguration?
-> TimelineProvider (placeholder / getSnapshot / getTimeline, completion-based)
AppIntentConfiguration?
-> AppIntentTimelineProvider (placeholder / snapshot(for:in:) / timeline(for:in:), async, intent FIRST)
RelevanceConfiguration (watchOS)?
-> RelevanceEntriesProvider (placeholder / relevance() / entry(configuration:context:), one entry per config)StaticConfiguration?
-> TimelineProvider (placeholder / getSnapshot / getTimeline,基于完成回调)
AppIntentConfiguration?
-> AppIntentTimelineProvider (placeholder / snapshot(for:in:) / timeline(for:in:),异步,意图为第一个参数)
RelevanceConfiguration(watchOS)?
-> RelevanceEntriesProvider (placeholder / relevance() / entry(configuration:context:),每个配置对应一个条目)Which reload policy?
使用哪种重载策略?
Next update time is known (countdown ends, event starts)?
-> .after(date)
Entries cover a window and the next batch can be computed at the end?
-> .atEnd
Content only changes from interaction / push, never on a schedule?
-> .never (then reload via WidgetCenter from an intent, app, or push)已知下次更新时间(倒计时结束、活动开始)?
-> .after(date)
条目覆盖一个时间段,且可在末尾计算下一批条目?
-> .atEnd
内容仅因交互/推送变化,无需定时更新?
-> .never (随后通过WidgetCenter从意图、应用或推送触发重载)Which interactive element?
使用哪种交互元素?
Inside a widget or Live Activity, runs an action?
-> Button(intent:) with an AppIntent (iOS 17+)
Inside a widget, binary on/off?
-> Toggle(isOn:intent:) with an AppIntent (iOS 17+)
Inside a Control Center control, binary on/off?
-> ControlWidgetToggle(action:) with a SetValueIntent
Inside a Control Center control, runs an action / opens the app?
-> ControlWidgetButton(action:) with an AppIntent (or OpenIntent to launch)在组件或Live Activity内,执行操作?
-> 搭配AppIntent的Button(intent:) (iOS 17+)
在组件内,二进制开关?
-> 搭配AppIntent的Toggle(isOn:intent:) (iOS 17+)
在控制中心控件内,二进制开关?
-> 搭配SetValueIntent的ControlWidgetToggle(action:)
在控制中心控件内,执行操作 / 打开应用?
-> 搭配AppIntent(或OpenIntent启动应用)的ControlWidgetButton(action:)Widget vs Live Activity vs Control?
组件 vs Live Activity vs 控件?
Glanceable data on a schedule, lives on Home/Lock Screen?
-> Widget (timeline)
Ongoing, time-bound event the user wants to watch live (delivery, game, workout)?
-> Live Activity (ActivityKit) - NOT a fast-reloading widget
A quick action or state toggle from Control Center / Lock Screen / Action button?
-> Control (ControlWidget)主屏幕/锁屏上的定时易读数据?
-> 组件(时间线)
用户需要实时关注的正在进行的限时事件(配送、游戏、锻炼)?
-> Live Activity(ActivityKit)- 不是高频重载的组件
从控制中心/锁屏/操作按钮快速执行操作或切换状态?
-> 控件(ControlWidget)Core Instructions
核心说明
- A widget runs in a separate extension process, not your app. It is always SwiftUI, even in a UIKit app. The system archives your view and renders it later - your code is not running while the widget is on screen. Share data with the app only through an App Group container (shared , a shared file, or a shared
UserDefaults(suiteName:)/Core Data store) - neverModelContainer, never in-memory singletons.UserDefaults.standard - Never make a widget interactive with a closure or . The only interactivity is
onTapGesture/Button(intent:)backed by anToggle(intent:)(iOS 17+), plusAppIntent/Linkfor deep links. Anything else silently does nothing.widgetURL - Always mark the widget's background with (iOS 17+). Without it the widget is blank in the gallery, can't be removed/relocated cleanly, and the system can't substitute the material background in Lock Screen / StandBy / tinted contexts. The container type is
.containerBackground(for: .widget) { ... }(valueContainerBackgroundPlacement) - there is no.widget.WidgetBackgroundPlacement - Never do blocking or asynchronous work in - it must return synchronously with stand-in data. Do real fetching in
placeholder(in:)/getSnapshot(or the asyncgetTimeline/snapshot). Usetimelinefor the first-render stand-in..redacted(reason: .placeholder) - (and
getSnapshot) is what the widget gallery shows - return realistic, populated sample data even when the user has none yet, never an empty/loading state.snapshot(for:in:) - Treat timeline reloads as a budgeted, opportunistic resource, not a timer. The system gives roughly 40-70 reloads/day per widget and learns from viewing habits. Never assume fires exactly on time. Provide multiple entries to cover a window, pick the policy that matches your data (
.after(date)/.atEnd/.after), and trigger a final.neverwhen the app enters the background if data changed.WidgetCenter.shared.reloadAllTimelines() - is a struct;
TimelineReloadPolicytakes a.after(_:), not aDate.TimeIntervaltakes the widget'sWidgetCenter.shared.reloadTimelines(ofKind:)string - keepkindvalues as shared constants so the app and extension can't drift.kind - For a configurable widget, use + a
AppIntentConfiguration(iOS 17+) and anWidgetConfigurationIntentwhoseAppIntentTimelineProvider/snapshottake the intent as the first argument.timelinelives in the AppIntents module and needs noWidgetConfigurationIntent. Provide sensibleperform()defaults; never force the user to configure before the widget shows anything.@Parameter - Never write a new configurable widget with the legacy SiriKit path - , an
IntentConfigurationfrom aINIntentfile, or.intentdefinition. Since iOS 17 the modern path is App Intents (IntentTimelineProvider+AppIntentConfiguration+WidgetConfigurationIntent). Only keep the legacy types behindAppIntentTimelineProviderwhen deploying below iOS 17, and when migrating an existing one conform the new intent to#availablewith the originalCustomIntentMigratedAppIntentso saved configurations survive. Likewise build watch complications with WidgetKit (+ aintentClassName), not ClockKit, and previews withCLKComplicationWidgetMigrator, not#Preview(as:). SeePreviewProvider.references/migration-and-deprecations.md - Don't fetch data inside the widget view (no , no network at render time) - the view is an archived snapshot rendered later. Resolve data and downsample images during timeline generation and put them in the entry, prefer reading an App-Group snapshot the app wrote, and always complete the provider (fall back to last-good data on error). See
AsyncImage.references/data-and-networking.md - Switch on and design each supported family deliberately. List only the families you actually lay out in
@Environment(\.widgetFamily)- shipping a family you didn't design looks broken. Accessory families (supportedFamilies/accessoryCircular/accessoryRectangular) are iOS 16+;accessoryInlineis watchOS only.accessoryCorner - Design for every rendering mode, not just full color. Read (
@Environment(\.widgetRenderingMode)/.fullColor/.accented); both.vibrantandWidgetRenderingModeare structs with type properties, not enums. InWidgetAccentedRenderingModemode the system flattens your view into two tint groups by alpha - put foreground content in the accent group with.accented, and control how images flatten with.widgetAccentable()(the image modifier is iOS 18+)..widgetAccentedRenderingMode(.desaturated / .accented / .accentedDesaturated / .fullColor) - For a multicolor image or icon that the accent group would crush into a flat silhouette: on iOS 18+ use (the system maps luminance to alpha and recolors for you); on iOS 17 and below that modifier doesn't exist, so apply the manual
.widgetAccentedRenderingMode(.desaturated)filter (bright pixels opaque, dark transparent) to preserve the shape's internal detail as a clean monochrome glyph - it also stays useful on iOS 18+ for hands-on control. Pair it with a soft gradient background and.luminanceToAlpha(). (See.widgetAccentable().)references/rendering-modes-and-tinting.md - For an accessory/Lock Screen widget or watch complication that should let the watch face or wallpaper show through, give it an empty . Omitting
.containerBackground(for: .widget) { }entirely makes the system add an opaque default material instead of a transparent one.containerBackground - An interactive runs in the app's process (the app is launched in the background if needed), not the widget extension - so it can write to the real data store. After it mutates data a widget displays, call
AppIntent(orWidgetCenter.shared.reloadTimelines(ofKind:)); for a control, callreloadAllTimelines(). Mark helper intents that only back a widget/control button withControlCenter.shared.reloadControls(ofKind:)so they don't pollute Shortcuts.static let isDiscoverable = false - In the 27 releases (iOS 27): a widget button's write intent must run on (the widget extension has a read-only view of the shared store). Pin it with
.main, and pin display-only intents withstatic var allowedExecutionTargets: ExecutionTargets { .main }..widgetKitExtension - A Control (, iOS 18; macOS/watchOS 26) uses
ControlWidgetwith aControlWidgetToggle(itsSetValueIntentis set by the system) orvalue: Boolwith a plainControlWidgetButton/AppIntent. The status modifier isOpenIntent- there is nocontrolWidgetStatus(_:). Provide acontrolWidgetStatusTextand an asyncpreviewValuein the value provider.currentValue - A Live Activity is the right tool for an ongoing, time-bound event - not a widget that reloads every few seconds. Split immutable data into and the only-updatable half into the nested
ActivityAttributes(keep it under 4 KB).ContentState: Codable, HashableandActivityConfigurationlive in WidgetKit;DynamicIslandand tokens live in ActivityKit.Activity.request/update/end/staleDateare set onrelevanceScore, not the configuration.ActivityContent.init - Live Activities require =
NSSupportsLiveActivitiesin the app's Info.plist; high-frequency push updates also needYES. Push-to-start usesNSSupportsLiveActivitiesFrequentUpdates(iOS 17.2+) - it is not aActivity.pushToStartTokencase. For mass-audience pushes use a broadcastPushType; otherwise per-activity push tokens.channel - Never put a animation in a Live Activity or widget - they aren't supported and silently no-op. Widget/Live Activity views are static snapshots; only
symbolEffecttimers/dates and the system's transition between timeline entries animate.Text(_:style:) - is iOS 18+; Controls are iOS 18+ (macOS/watchOS 26+); push-updated widgets (
widgetAccentedRenderingMode) andWidgetPushHandlerare iOS 26 / watchOS 26; spatial-widget modifiers (RelevanceConfiguration,supportedMountingStyles,widgetTexture) are iOS/visionOS 26;levelOfDetail, the landscape Dynamic Island (systemExtraLargePortrait), andisDynamicIslandLimitedInWidthare part of the 27 releases. Gate each behind the correct availability and call the WWDC 2026 cohort "the 27 releases", not "iOS 19".allowedExecutionTargets - Use the macro (iOS 17+) to iterate on widgets across families, color schemes, and rendering modes without running the host app; enable WidgetKit developer mode (Settings ▸ Developer) to lift the reload budget while iterating. The reload budget being exhausted - not a code bug - is the most common reason a widget "stops updating".
#Preview(as:)
- 组件运行在独立的扩展进程中,而非你的应用进程。它始终基于SwiftUI,即使在UIKit应用中也是如此。系统会归档你的视图并在稍后渲染——组件显示时你的代码并未运行。仅通过App Group容器与应用共享数据(共享、共享文件或共享
UserDefaults(suiteName:)/Core Data存储)——绝不能使用ModelContainer或内存单例。UserDefaults.standard - 绝不能使用闭包或实现组件交互。唯一支持的交互方式是基于
onTapGesture的AppIntent/Button(intent:)(iOS 17+),以及用于深度链接的Toggle(intent:)/Link。其他方式会静默失效。widgetURL - 必须使用(iOS 17+)标记组件背景。如果不设置,组件在组件库中会显示空白,无法正常删除/移动,且系统无法在锁屏/StandBy/着色场景下替换为材质背景。容器类型为
.containerBackground(for: .widget) { ... }(值为ContainerBackgroundPlacement)——不存在.widget。WidgetBackgroundPlacement - 绝不能在中执行阻塞或异步操作——必须同步返回占位数据。在
placeholder(in:)/getSnapshot(或异步的getTimeline/snapshot)中执行真实的数据获取。使用timeline作为首次渲染的占位符。.redacted(reason: .placeholder) - (以及
getSnapshot)是组件库展示的内容——即使用户尚未有数据,也需返回真实的填充样本数据,绝不能返回空/加载状态。snapshot(for:in:) - 将时间线重载视为有预算、机会性的资源,而非定时器。系统每天为每个组件提供约40-70次重载机会,并会根据用户查看习惯学习调整。绝不能假设会准时触发。提供多个条目覆盖一个时间段,选择与数据匹配的策略(
.after(date)/.atEnd/.after),如果数据发生变化,在应用进入后台时调用.never。WidgetCenter.shared.reloadAllTimelines() - 是一个结构体;
TimelineReloadPolicy接收**.after(_:)**类型参数,而非Date。TimeInterval接收组件的WidgetCenter.shared.reloadTimelines(ofKind:)字符串——将kind值设为共享常量,避免应用和扩展出现不一致。kind - 对于可配置组件,使用+
AppIntentConfiguration(iOS 17+),以及WidgetConfigurationIntent/snapshot将意图作为第一个参数的timeline。AppIntentTimelineProvider属于AppIntents模块,无需实现WidgetConfigurationIntent。为perform()提供合理的默认值;绝不能强制用户先配置再显示组件。@Parameter - 绝不能使用旧版SiriKit路径编写新的可配置组件——包括、来自
IntentConfiguration文件的.intentdefinition或INIntent。自iOS 17起,现代方案是App Intents(IntentTimelineProvider+AppIntentConfiguration+WidgetConfigurationIntent)。仅在部署到iOS 17以下版本时,在AppIntentTimelineProvider保留旧版类型;迁移现有组件时,让新意图遵循#available并保留原始CustomIntentMigratedAppIntent,确保已保存的配置不会丢失。同样,使用WidgetKit(搭配intentClassName)构建手表复杂功能,而非ClockKit;使用CLKComplicationWidgetMigrator构建预览,而非#Preview(as:)。详见PreviewProvider。references/migration-and-deprecations.md - 不要在组件视图内获取数据(不使用,渲染时不发起网络请求)——视图是归档的快照,会在稍后渲染。在时间线生成期间解析数据并对图片进行降采样,将其放入条目中;优先读取应用写入的App Group快照;提供者始终要完成执行(出错时回退到上次的有效数据)。详见
AsyncImage。references/data-and-networking.md - 根据进行分支,为每个支持的家族设计专属布局。在
@Environment(\.widgetFamily)中仅列出实际设计过的家族——发布未设计的家族会显示异常。附属组件家族(supportedFamilies/accessoryCircular/accessoryRectangular)为iOS 16+;accessoryInline仅适用于watchOS。accessoryCorner - 为所有渲染模式设计,而非仅全彩模式。读取(
@Environment(\.widgetRenderingMode)/.fullColor/.accented);.vibrant和WidgetRenderingMode都是带类型属性的结构体,而非枚举。在WidgetAccentedRenderingMode模式下,系统会通过透明度将视图扁平化为两个着色组——使用.accented将前景内容放入着色组,并使用.widgetAccentable()控制图片的扁平化方式(该图片修饰符为iOS 18+)。.widgetAccentedRenderingMode(.desaturated / .accented / .accentedDesaturated / .fullColor) - 对于会被着色组压平为扁平轮廓的多色图片或图标:在iOS 18+上使用(系统会将亮度映射为透明度并重新着色);在iOS 17及以下版本中该修饰符不存在,因此手动应用
.widgetAccentedRenderingMode(.desaturated)滤镜(亮像素不透明,暗像素透明),以保留形状的内部细节,使其成为清晰的单色符号——该方式在iOS 18+上也可用于手动控制。搭配柔和渐变背景和.luminanceToAlpha()使用。(详见.widgetAccentable()。)references/rendering-modes-and-tinting.md - 对于需要让表盘或壁纸透出来的附属/锁屏组件或手表复杂功能,设置空的。完全省略
.containerBackground(for: .widget) { }会让系统添加不透明的默认材质,而非透明背景。containerBackground - 交互式运行在应用进程中(必要时应用会在后台启动),而非组件扩展进程——因此它可以写入真实的数据存储。在修改组件显示的数据后,调用
AppIntent(或WidgetCenter.shared.reloadTimelines(ofKind:));对于控件,调用reloadAllTimelines()。将仅支持组件/控件按钮的辅助意图标记为ControlCenter.shared.reloadControls(ofKind:),避免污染快捷指令。static let isDiscoverable = false - 在27版本(iOS 27)中:组件按钮的写入意图必须在运行(组件扩展对共享存储只有只读权限)。使用
.main指定,将仅用于显示的意图指定为static var allowedExecutionTargets: ExecutionTargets { .main }。.widgetKitExtension - 控件(,iOS 18;macOS/watchOS 26)使用搭配**
ControlWidget**的SetValueIntent(其ControlWidgetToggle由系统设置),或搭配普通value: Bool/AppIntent的OpenIntent。状态修饰符为ControlWidgetButton——不存在controlWidgetStatus(_:)。在值提供者中提供controlWidgetStatusText和异步previewValue。currentValue - Live Activity适用于正在进行的限时事件——而非每隔几秒重载一次的组件。将不可变数据拆分为,将仅可更新的部分放入嵌套的
ActivityAttributes(保持大小在4KB以下)。ContentState: Codable, Hashable和ActivityConfiguration属于WidgetKit;DynamicIsland和令牌属于ActivityKit。Activity.request/update/end/staleDate设置在relevanceScore中,而非配置中。ActivityContent.init - Live Activities需要在应用的Info.plist中设置=
NSSupportsLiveActivities;高频推送更新还需要YES。推送启动使用NSSupportsLiveActivitiesFrequentUpdates(iOS 17.2+)——它不是Activity.pushToStartToken的枚举值。面向大量受众的推送使用广播PushType;否则使用每个活动的推送令牌。channel - 绝不能在Live Activity或组件中添加动画——它们不受支持,会静默失效。组件/Live Activity视图是静态快照;只有
symbolEffect计时器/日期和系统在时间线条目间的过渡会动画。Text(_:style:) - 为iOS 18+;控件为iOS 18+(macOS/watchOS 26+);推送更新组件(
widgetAccentedRenderingMode)和WidgetPushHandler为iOS 26 / watchOS 26;空间组件修饰符(RelevanceConfiguration、supportedMountingStyles、widgetTexture)为iOS/visionOS 26;levelOfDetail、横屏灵动岛(systemExtraLargePortrait)和isDynamicIslandLimitedInWidth属于27版本。为每个功能添加正确的可用性判断,并将WWDC 2026系列版本称为**"27版本"**,而非"iOS 19"。allowedExecutionTargets - 使用宏(iOS 17+)在不运行宿主应用的情况下,跨组件家族、配色方案和渲染模式迭代开发;启用WidgetKit开发者模式(设置 ▸ 开发者)以在迭代时解除重载预算限制。重载预算耗尽——而非代码bug——是组件"停止更新"的最常见原因。
#Preview(as:)
Output Format
输出格式
If the user asks for a review, organize findings by file. For each issue:
- State the file and relevant line(s).
- Name the anti-pattern being replaced.
- Show a brief before/after code fix.
Skip files with no issues. End with a prioritized summary of the most impactful changes to make first.
If the user asks you to write or fix widget code, make the changes directly instead of returning a findings report.
Example output:
如果用户要求审查,按文件整理发现的问题。每个问题包含:
- 说明文件及相关行号。
- 指出要替换的反模式。
- 展示简短的修复前后代码对比。
跳过无问题的文件。最后给出优先级排序的摘要,列出最需优先修改的关键变更。
如果用户要求编写或修复组件代码,直接修改代码,而非返回问题报告。
示例输出:
CaffeineWidget.swift
CaffeineWidget.swift
Line 14: does a synchronous disk fetch - placeholders must return instantly.
placeholder(in:)swift
// Before
func placeholder(in context: Context) -> Entry {
Entry(date: .now, drinks: Store.shared.loadAllDrinks()) // blocks the render
}
// After
func placeholder(in context: Context) -> Entry {
Entry(date: .now, drinks: .sample) // synchronous stand-in; real data in getTimeline
}Line 41: interactive in a widget does nothing - use an App Intent.
onTapGestureswift
// Before
Image(systemName: "plus.circle").onTapGesture { addDrink() }
// After
Button(intent: AddDrinkIntent()) { Image(systemName: "plus.circle") }
// AddDrinkIntent.perform() writes to the App Group store, then:
// WidgetCenter.shared.reloadTimelines(ofKind: "CaffeineWidget")第14行:执行同步磁盘读取——占位符必须立即返回。
placeholder(in:)swift
// 修复前
func placeholder(in context: Context) -> Entry {
Entry(date: .now, drinks: Store.shared.loadAllDrinks()) // 阻塞渲染
}
// 修复后
func placeholder(in context: Context) -> Entry {
Entry(date: .now, drinks: .sample) // 同步占位数据;真实数据在getTimeline中获取
}第41行:组件中的交互式无效——使用App Intent。
onTapGestureswift
// 修复前
Image(systemName: "plus.circle").onTapGesture { addDrink() }
// 修复后
Button(intent: AddDrinkIntent()) { Image(systemName: "plus.circle") }
// AddDrinkIntent.perform()写入App Group存储,然后调用:
// WidgetCenter.shared.reloadTimelines(ofKind: "CaffeineWidget")Summary
摘要
- Placeholder (high): must be synchronous; move fetching to the timeline.
- Interactivity (high): gestures don't work in widgets; back the tap with an .
AppIntent
End of example.
- 占位符(高优先级): 必须同步;将数据获取移至时间线。
- 交互性(高优先级): 手势在组件中无效;使用支持点击操作。
AppIntent
示例结束。
References
参考文件
- - the widget execution model: the extension process, app groups,
references/fundamentals.md, theWidgetBundleprotocol, the timeline lifecycle,Widget, content margins, deep linking,containerBackground, and the "which surface" map.kind - -
references/timeline-provider.mdvsTimelineProvider,AppIntentTimelineProvider,TimelineEntry, reload policies, the reload budget,Timelinereloads, reload-on-background,WidgetCenter.TimelineEntryRelevance - -
references/configuration-and-intents.md,StaticConfiguration,AppIntentConfiguration, dynamic options / entity parameters,WidgetConfigurationIntent, defaults.recommendations() - - the old → new map: SiriKit
references/migration-and-deprecations.md/.intentdefinition→ App Intents,IntentConfiguration→IntentTimelineProvider, ClockKit → WidgetKit,AppIntentTimelineProvider→PreviewProvider, what's deprecated vs legacy-but-supported,#Preview.CustomIntentMigratedAppIntent - - loading data for timelines: App Group snapshots,
references/data-and-networking.md/backgroundasyncfetches, image downsampling, SwiftData/Core Data in widgets, location, Lock Screen privacy.URLSession - -
references/families-and-layout.mdcases, sizing,WidgetFamily, content margins, the per-family switch,supportedFamilies,ViewThatFits.ContainerRelativeShape - - accessory families, watch complications,
references/lock-screen-and-watch.md,widgetLabel, gauges, the transparentAccessoryWidgetBackgroundtrick, ClockKit → WidgetKit migration.containerBackground - -
references/rendering-modes-and-tinting.md(widgetRenderingMode/.fullColor/.accented),.vibrant,widgetAccentable, the luminance-to-alpha trick, designing for the tinted/clear Home Screen and accent groups.widgetAccentedRenderingMode - -
references/interactive-widgets.md/Button(intent:), the app-process boundary,Toggle(intent:)persistence, the App Group store,@Parameter, the optimisticreloadTimelines,ToggleStyle,invalidatableContent,isDiscoverable(the 27 releases).allowedExecutionTargets - -
references/deep-linking-and-navigation.mdvswidgetURL, per-family tap rules, URL-scheme design, handling on the app side (Link/ scene delegate), Live ActivityonOpenURL/widgetURL, controlkeylineTint.OpenIntent - - the entry-diffing animation model,
references/animations-and-transitions.md,contentTransition(.numericText)+.transitionidentity, the optimistic.id,Toggle, Live Activity transitions, what does not animate (invalidatableContent, loops, video).symbolEffect - -
references/controls.md,ControlWidget/StaticControlConfiguration,AppIntentControlConfiguration(ControlWidgetToggle) vsSetValueIntent(ControlWidgetButton/AppIntent), value providers,OpenIntentreloads, status/action-hint modifiers, platforms.ControlCenter - -
references/live-activities.md/ActivityAttributes,ContentState,ActivityConfiguration,DynamicIsland,Activity.request/update/endstaleness, push (token / channel / push-to-start),ActivityContent/supplementalActivityFamilies, the landscape Dynamic Island, StandBy,activityFamily, entitlements.LiveActivityIntent - -
references/relevance-and-smart-stacks.md,TimelineEntryRelevance+relevance()/WidgetRelevance/WidgetRelevanceAttribute,RelevantContext+RelevanceConfiguration(watchOS 26), push-updated widgets (RelevanceEntriesProvider, iOS 26), Smart Stack behavior.WidgetPushHandler - - the design rules (glanceable/relevant/personal, not a mini-app), sizes & tap styles, layout margins & type, the explicit don'ts, the gallery (
references/design-and-gallery.md/configurationDisplayName/snapshot), the placeholder, personalization, Smart Stack etiquette.description - - the
references/previews-and-testing.mdmacro variants,#Preview(as:), testing rendering modes/families, WidgetKit developer mode, the reload budget, debugging "won't update".WidgetPreviewContext - - visionOS spatial widgets (
references/platforms.md,supportedMountingStyles,widgetTexture,levelOfDetail), CarPlay widgets and Live Activities, macOS menu bar, watchOS, the cross-platform availability map.systemExtraLargePortrait - - one widget built end to end (a
references/worked-example.mdQuick Actions widget): entry + provider, multi-systemMediumlayout, full-color-vs-tinted handling, an entry-drivenLinkanimation,MeshGradient, and the preview - with pointers to the deeper reference for each step.contentMarginsDisabled - - the consolidated smell → fix checklist, including the API-name confusions LLMs make (struct vs enum rendering modes,
references/anti-patterns.md,ContainerBackgroundPlacement,pushToStartToken).controlWidgetStatus
- - 组件执行模型:扩展进程、应用组、
references/fundamentals.md、WidgetBundle协议、时间线生命周期、Widget、内容边距、深度链接、containerBackground、界面场景映射。kind - -
references/timeline-provider.mdvsTimelineProvider、AppIntentTimelineProvider、TimelineEntry、重载策略、重载预算、Timeline重载、后台重载、WidgetCenter。TimelineEntryRelevance - -
references/configuration-and-intents.md、StaticConfiguration、AppIntentConfiguration、动态选项 / 实体参数、WidgetConfigurationIntent、默认值。recommendations() - - 新旧映射:SiriKit
references/migration-and-deprecations.md/.intentdefinition→ App Intents、IntentConfiguration→IntentTimelineProvider、ClockKit → WidgetKit、AppIntentTimelineProvider→PreviewProvider、已废弃与仍支持的旧版API、#Preview。CustomIntentMigratedAppIntent - - 时间线数据加载:App Group快照、
references/data-and-networking.md/后台async请求、图片降采样、组件中的SwiftData/Core Data、位置信息、锁屏隐私。URLSession - -
references/families-and-layout.md枚举值、尺寸、WidgetFamily、内容边距、按家族分支、supportedFamilies、ViewThatFits。ContainerRelativeShape - - 附属组件家族、手表复杂功能、
references/lock-screen-and-watch.md、widgetLabel、仪表盘、透明容器技巧、ClockKit → WidgetKit迁移。AccessoryWidgetBackground - -
references/rendering-modes-and-tinting.md(widgetRenderingMode/.fullColor/.accented)、.vibrant、widgetAccentable、亮度转透明度技巧、为着色/透明主屏幕和着色组设计。widgetAccentedRenderingMode - -
references/interactive-widgets.md/Button(intent:)、应用进程边界、Toggle(intent:)持久化、App Group存储、@Parameter、乐观reloadTimelines、ToggleStyle、invalidatableContent、isDiscoverable(27版本)。allowedExecutionTargets - -
references/deep-linking-and-navigation.mdvswidgetURL、按家族点击规则、URL scheme设计、应用端处理(Link/ 场景代理)、Live ActivityonOpenURL/widgetURL、控件keylineTint。OpenIntent - - 条目差异动画模型、
references/animations-and-transitions.md、contentTransition(.numericText)+.transition标识、乐观.id、Toggle、Live Activity过渡、不支持动画的内容(invalidatableContent、循环、视频)。symbolEffect - -
references/controls.md、ControlWidget/StaticControlConfiguration、AppIntentControlConfiguration(ControlWidgetToggle) vsSetValueIntent(ControlWidgetButton/AppIntent)、值提供者、OpenIntent重载、状态/操作提示修饰符、平台支持。ControlCenter - -
references/live-activities.md/ActivityAttributes、ContentState、ActivityConfiguration、DynamicIsland、Activity.request/update/end过期、推送(令牌 / 频道 / 推送启动)、ActivityContent/supplementalActivityFamilies、横屏灵动岛、StandBy、activityFamily、权限。LiveActivityIntent - -
references/relevance-and-smart-stacks.md、TimelineEntryRelevance+relevance()/WidgetRelevance/WidgetRelevanceAttribute、RelevantContext+RelevanceConfiguration(watchOS 26)、推送更新组件(RelevanceEntriesProvider, iOS 26)、智能堆栈行为。WidgetPushHandler - - 设计规则(易读/相关/个性化,不是迷你应用)、尺寸与点击样式、布局边距与字体、明确的禁忌、组件库(
references/design-and-gallery.md/configurationDisplayName/快照)、占位符、个性化、智能堆栈规范。description - -
references/previews-and-testing.md宏变体、#Preview(as:)、测试渲染模式/家族、WidgetKit开发者模式、重载预算、调试"无法更新"问题。WidgetPreviewContext - - visionOS空间组件(
references/platforms.md、supportedMountingStyles、widgetTexture、levelOfDetail)、CarPlay组件和Live Activities、macOS菜单栏、watchOS、跨平台可用性映射。systemExtraLargePortrait - - 端到端构建一个组件(
references/worked-example.md快速操作组件):条目 + 提供者、多systemMedium布局、全彩与着色模式处理、条目驱动的Link动画、MeshGradient、预览——每个步骤都指向更深入的参考文件。contentMarginsDisabled - - 整合的问题→修复清单,包括LLMs常犯的API名称混淆(结构体vs枚举渲染模式、
references/anti-patterns.md、ContainerBackgroundPlacement、pushToStartToken)。",controlWidgetStatus