iOS 26 的小组件界面:一个 App Intent,多处呈现
多年来,小组件不过是一张快照。系统按时间线渲染出您的视图,用户看一眼,任何点按都只会打开应用。这套模式已成过去。自 iOS 17 起,小组件就能承载按钮和开关,无需启动任何东西即可运行代码,而它们运行的正是一个 App Intent1。控制中心控件如此,实时活动内部的按钮也是如此。一旦看清这一点,iOS 26 的小组件界面就不再像三个彼此独立的 API,而是合而为一:它们都是系统呈现您 App Intents 的场所,各自占据不同的展示空间,底层却共用同一套管道。
这种重新审视,正是本文的核心。学会一次 App Intent,就能点亮主屏幕、锁定屏幕、控制中心、操作按钮、灵动岛,以及(还是同一个 intent)Siri 与 Apple Intelligence。若把它们当成三个互不相干的功能去写,您将付出四倍的工作量,结果反而更糟。
太长不看
- 可交互小组件(iOS 17 及以上): 在小组件视图里放一个
Button(intent:)或Toggle(isOn:intent:);系统会在您的小组件扩展中、脱离应用运行该 App Intent 的perform(),随后重新加载时间线1。 - 控制中心控件(iOS 18 及以上): 由
ControlWidgetButton或ControlWidgetToggle构建的ControlWidget,背后同样是 App Intents,会出现在控制中心、锁定屏幕以及操作按钮上2。 - 实时活动(ActivityKit):
ActivityAttributes加上ActivityConfiguration驱动锁定屏幕与灵动岛;由服务器驱动的更新通过推送送达,其中的按钮同样是 App Intents3。 - iOS 26 改变的是呈现方式,而非模型本身: 小组件采用了 Liquid Glass 外观和着色渲染模式,但「App Intents 即界面」的架构与 iOS 18 相比并无变化4。
- 统一的事实在于:一个小组件按钮、一个控件、一句 Siri 指令、一次 Apple Intelligence 操作,都可以是同一个 App Intent。能力只需设计一次。
可交互小组件:不打开应用的按钮
机制很简单,值得把话说精确。您给小组件视图添加一个 SwiftUI Button 或 Toggle,但传入的不是动作闭包,而是一个 App Intent1:
struct WaterWidgetView: View {
let logged: Int
var body: some View {
VStack {
Text("\(logged) glasses")
Button(intent: LogWaterIntent()) {
Label("Add", systemImage: "plus")
}
}
}
}
用户点按时,系统会在您的小组件扩展内运行 LogWaterIntent.perform()。应用不会启动。intent 完成自己的工作(写入共享存储、更新计数),随后小组件时间线重新加载,显示结果。
Toggle 通过 SetValueIntent 以同样的方式运作,它会接收到用户刚刚设定的新开/关值:
struct ToggleReminderIntent: SetValueIntent {
static let title: LocalizedStringResource = "Toggle Reminder"
@Parameter(title: "Enabled")
var value: Bool
func perform() async throws -> some IntentResult {
ReminderStore.shared.enabled = value
return .result()
}
}
小组件绑定 Toggle(isOn: store.enabled, intent: ToggleReminderIntent()),系统把 value 设为新状态,运行 perform(),然后重新加载。与按钮形态如出一辙,只是多了一个参数1。
有两条约束决定了您在这里能做什么,两者都很容易踩坑。其一,perform() 运行在受限的小组件扩展环境中,执行预算十分紧张;它适合快速的状态变更,而非网络上传或繁重计算。其二,小组件反映状态,并不能随意做 UI 动画。您改变数据,时间线重新渲染;您无法运行自定义过渡动画。把交互设计成「翻转一个值,显示新值」,它就能跑通。一旦贪多,系统就会跟您较劲。
控制中心控件:同一个 intent,换一个房间
iOS 18 把控制中心、锁定屏幕和操作按钮向第三方控件开放,而其 API 与小组件有意保持平行2。一个控件就是一个 ControlWidget,其主体是接到某个 App Intent 上的 ControlWidgetButton 或 ControlWidgetToggle:
struct LogWaterControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "com.example.logWater") {
ControlWidgetButton(action: LogWaterIntent()) {
Label("Log Water", systemImage: "drop.fill")
}
}
}
}
如果 LogWaterIntent 已经在驱动您的可交互小组件,那这个控件几乎是白送的:同一个 intent,换个外壳而已。这正是架构带来的回报。控件并不是该功能的第二份实现,而是您早已写好的那份功能的第二个挂载点。开关控件使用 SetValueIntent,方式与小组件开关完全一致,于是一项「静音」「开始会话」或「切换深色模式」的能力只需构建一次,就能出现在控制中心、锁定屏幕和操作按钮上,无需新增任何逻辑2。
实时活动:会自我更新的界面
实时活动是第三处场所,也是活动部件最多的一处。ActivityAttributes 类型定义静态与动态内容,ActivityConfiguration 渲染锁定屏幕的呈现样式和灵动岛的各个区域,ActivityKit 则负责启动、更新和结束活动3。实时活动内部的按钮,依然是 App Intents,因此灵动岛里的「暂停」或「下一个」控件,运行的与小组件按钮属于同一类 intent。
让实时活动自成一门学问的,是其更新路径。本地更新的计时器很简单。但若活动是由服务器上发生的事件驱动的(一份外卖正在移动、一场比赛比分在变化),更新就通过推送进行:您注册 pushTokenUpdates,从后端发送 ActivityKit 推送负载,系统便会在您的应用根本没有运行的情况下更新锁定屏幕和灵动岛3。这确实强大,也确实极易出错,因为此时活动的正确性不再只取决于本地代码,而是取决于服务器契约、推送可靠性,以及一套过期时间策略。
iOS 26 到底改了什么
iOS 26 小组件的看点是呈现,而非架构。小组件采用了 Liquid Glass 材质,新增了着色渲染模式,从而契合系统全新的设计语言,并在操作系统重新着色内容的场景中正确染色4。这关系到小组件在主屏幕、锁定屏幕和待机显示中的观感,值得专门做一轮设计打磨。但它并未改变交互的工作方式。如果您早在 iOS 18 就构建了可交互小组件和控件,那么在 iOS 26 上要做的只是视觉焕新,而非重写。对于声称 iOS 26「引入」了可交互小组件的说法,请保持警惕;交互能力在 iOS 17 就已发布,控件在 iOS 18 发布,iOS 26 只是让它们看起来与系统其余部分浑然一体。
不过,Liquid Glass 带来的设计影响是实实在在的。小组件是系统叠加在墙纸之上、并经玻璃质感界面折射的内容,因此管辖 应用内 Liquid Glass 的那些规则在此同样适用:尊重「功能层与内容层」的分层,不要用玻璃读不出来的厚重自定义背景去对抗这种材质。
把架构讲清楚
这里有一个值得牢记的模型。一个 App Intent 是一项有名称、有类型、有描述的能力。iOS 给您提供了越来越多挂载这项能力的场所:
- 小组件内的
Button或Toggle。 - 控制中心、锁定屏幕和操作按钮中的
ControlWidget。 - 实时活动及其灵动岛内的按钮。
- 一句 Siri 指令和一个快捷指令操作。
- Apple Intelligence 可代用户调用的一项操作5。
这其中的每一处,都是同一个带 perform() 方法的 AppIntent 类型。功夫全在于把那项能力设计好:一个清晰的名称、带类型的参数、一个快速且幂等的 perform(),以及一个合理的结果。把这件事做好一次,各处界面就只是外壳。这正是我此前论述过的同一个观点——App Intents 是 通向您应用的真正 API,以及一个 iOS 应用如今暴露出的 三个界面:小组件界面不是您去构建的一项功能,而是您的各项能力一旦存在便会现身的场所。
何时不必费这个劲
小组件界面回报的是那些真正具备一目了然状态和快捷操作的应用:追踪器、计时器、开关、正在播放控件。它并不回报所有应用。
- 没有一目了然的状态,就别做小组件。 如果不打开应用就没什么值得展示的东西,那小组件只是装饰,徒增维护负担和一个额外的扩展目标。
- 繁重或缓慢的操作不该放进这里的
perform()。 小组件和控件的执行环境是受限的。如果操作需要真正的时间或算力,按钮就应当打开应用、进入一个准备好的状态,而不是假装在扩展里把活干了。 - 为并非「实时」的东西做实时活动。 实时活动面向的是有时限、正在主动变化的事件。把它当成常驻状态徽章来用,是对这一界面的误读,也是迅速登上系统活动预算黑名单的捷径。
真正的本事,不是学会三种 API,而是设计出值得挂载的 App Intents,然后把它们挂到用户本就在的地方:他们会查看的主屏幕、会上滑唤出的控制中心、已经在向他们展示信息的灵动岛。带着品味把能力构建一次,iOS 便会把各处界面免费奉上。
-
Apple Developer,“Adding interactivity to widgets and Live Activities”。可交互小组件(iOS 17 及以上)使用以
AppIntent(开关则用SetValueIntent)为后盾的 SwiftUIButton(intent:)和Toggle(isOn:intent:);intent 的perform()在小组件扩展中运行,不启动应用,随后时间线重新加载以反映结果。 ↩↩↩↩ -
Apple Developer,“Creating controls to perform actions across the system” 及
ControlWidget协议。控件(iOS 18 及以上)由接到 App Intents 上的ControlWidgetButton和ControlWidgetToggle构建,出现在控制中心、锁定屏幕以及操作按钮上。 ↩↩↩ -
Apple Developer,“ActivityKit” 及 “Displaying live data with Live Activities”。
ActivityAttributes与ActivityConfiguration定义并渲染锁定屏幕和灵动岛;ActivityKit 负责启动、更新和结束活动,而服务器驱动的更新通过pushTokenUpdates使用推送。 ↩↩↩ -
iOS 26 小组件渲染:小组件采用 Liquid Glass 材质和着色渲染模式,通过
WidgetRenderingMode及\.widgetRenderingMode环境值控制。交互模型(小组件和控件中的 App Intents)与 iOS 17(小组件)和 iOS 18(控件)相比并无变化。Apple,“WWDC 2025: the new software design” 及 WidgetKit 文档。 ↩↩ -
Apple Developer,“App Intents”。同一个
AppIntent类型,正是系统通过 Siri、快捷指令、聚焦搜索、小组件与控件界面,以及 Apple Intelligence 所暴露的那个单元。作者对跨界面模型的分析:App Intents 是 Apple 通向您应用的全新 API、App Intents 2 与 iOS 26 的新增能力,以及 一个 iOS 应用的三个界面。 ↩