How it works
WidgetBundle is the protocol you adopt to ship more than one kind of widget from a single widget extension. A widget extension has exactly one entry point, so when your app offers several distinct widgets — a calendar, a weather glance, a reminders list — you group them under one WidgetBundle rather than declaring each in isolation. Reach for it whenever a target needs to vend multiple widgets, including Live Activities, so the system can present them all in the widget gallery for the user to add.
Adopt WidgetBundle and mark the entry point
Conform a type to
WidgetBundleand annotate it with@mainto make it the widget extension's single entry point, just as@mainmarks an app'sApptype. The conforming type carries no stored state of its own; its whole job is to enumerate the widgets the extension provides, the wayWidgetBundleDemohere enumerates the namesCalendar,Weather, andReminders.List the widgets in the body property
Implement the required
bodyproperty, whose return type conforms to theWidgetprotocol. Inside it you list each widget value — one per kind you want to publish — and the system registers every one. Each entry corresponds to a configured widget, much as eachnamein theForEachoverwidgetsstands for one item in the bundle.Compose with @WidgetBundleBuilder
The
bodyproperty is a@WidgetBundleBuilderresult builder, so you write the widgets as a plain sequence of expressions rather than assembling an array by hand. The builder also lets you branch withifandif #availableto conditionally include a widget — for example, gating a Live Activity on the OS version — so a single bundle can adapt its offerings to the running platform.Combine different widget configurations
A bundle can mix
StaticConfiguration,AppIntentConfiguration, and Live Activity widgets freely; each retains its own kind, supported families, and configuration UI. Grouping them under oneWidgetBundleonly collects them into a single extension — it does not flatten or merge their behavior, so the three conceptual entries shown asCalendar,Weather, andReminderswould each keep distinct timelines and supported sizes.
"Stocks" to the widgets array to see how a WidgetBundle grows simply by listing one more widget in its body.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct WidgetBundleDemo: View {
let widgets = ["Calendar", "Weather", "Reminders"]
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Text("My Widget Bundle")
.font(.headline)
ForEach(widgets, id: \.self) { name in
HStack {
Image(systemName: "square.grid.2x2")
Text(name)
Spacer()
}
.padding()
.background(Color(.systemGray6))
.cornerRadius(10)
}
}
.padding()
}
}