2025 Health & FitnessMaps & LocationSwiftUI & UI Frameworks
WWDC25 · 21 min · Health & Fitness / Maps & Location / SwiftUI & UI Frameworks
What’s new in watchOS 26
Discover the new features in watchOS 26 and learn how to integrate them into your watchOS and iOS apps. Explore the ARM64 architecture, and dive into the new design system. We’ll also share updates for widgets and insights on how to bring controls to Apple Watch.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 13 snippets
Make a widget configurable
// In the AppIntentTimelineProvider
func recommendations() -> [AppIntentRecommendation<BeachConfigurationIntent>] {
return []
} Support earlier versions of watchOS with a configurable widget
// In the AppIntentTimelineProvider
func recommendations() -> [AppIntentRecommendation<BeachConfigurationIntent>] {
if #available(watchOS 26, *) {
// Return an empty array to allow configuration of the widget in watchOS 12+
return []
} else {
// Return array of recommendations for preconfigured widgets before watchOS 12
return recommendedBeaches
}
} Use AppIntentControlConfiguration to make a control configurable
struct ConfigurableMeditationControl: ControlWidget {
var body: some ControlWidgetConfiguration {
AppIntentControlConfiguration(
kind: WidgetKinds.configurableMeditationControl,
provider: Provider()
) { value in
// Provide the control's content
}
.displayName("Ocean Meditation")
.description("Meditation with optional ocean sounds.")
.promptsForUserConfiguration()
}
} Use AppIntentControlValueProvider for a configurable control
extension ConfigurableMeditationControl {
struct Provider: AppIntentControlValueProvider {
func previewValue(configuration: TimerConfiguration) -> Value {
// Return the value to show in the add sheet
}
func currentValue(configuration: TimerConfiguration) async throws -> Value {
// Return the control's value
}
}
} Relevance for a point-of-interest category
func relevance() async -> WidgetRelevance<Void> {
guard let context = RelevantContext.location(category: .beach) else {
return WidgetRelevance<Void>([])
}
return WidgetRelevance([WidgetRelevanceAttribute(context: context)])
} Implement the relevance method in the RelevanceEntriesProvider
struct BeachEventRelevanceProvider: RelevanceEntriesProvider {
let store: BeachEventStore
func relevance() async -> WidgetRelevance<BeachEventConfigurationIntent> {
// Associate configuration intents with RelevantContexts
let attributes = events.map { event in
WidgetRelevanceAttribute(
configuration: BeachEventConfigurationIntent(event: event),
context: .date(interval: event.date, kind: .default)
)
}
return WidgetRelevance(attributes)
}
} Create a RelevanceEntry when the widget is relevant
struct BeachEventRelevanceProvider: RelevanceEntriesProvider {
func relevance() async -> WidgetRelevance<BeachEventConfigurationIntent> {
// Return relevance information for the widget
}
func entry(
configuration: BeachEventConfigurationIntent,
context: Context
) async throws -> BeachEventRelevanceEntry {
if context.isPreview {
return .previewEntry
}
return BeachEventRelevanceEntry(
event: configuration.event
)
}
} Create a placeholder entry to display when the widget is loading
struct BeachEventRelevanceProvider: RelevanceEntriesProvider {
func relevance() async -> WidgetRelevance<BeachEventConfigurationIntent> {
// Return relevance information for the widget
}
func entry(
configuration: BeachEventConfigurationIntent,
context: Context
) async throws -> BeachEventRelevanceEntry {
// Return the entry for the configuration
}
func placeholder(context: Context) -> BeachEventRelevanceEntry {
BeachEventRelevanceEntry.placeholderEntry
}
} Use a RelevanceConfiguration to create a relevant widget
struct BeachEventWidget: Widget {
private let model = BeachEventStore.shared
var body: some WidgetConfiguration {
RelevanceConfiguration
kind: "BeachWidget
provider: BeachEventRelevanceProvider(store: model)
) { entry in
BeachWidgetView(entry: entry)
}
.configurationDisplayName("Beach Events")
.description("Events at the beach")
}
} Use associatedKind to relate the relevant widget to the timeline widget
struct BeachEventWidget: Widget {
private let model = BeachEventStore.shared
var body: some WidgetConfiguration {
RelevanceConfiguration
kind: "BeachWidget
provider: BeachEventRelevanceProvider(store: model)
) { entry in
BeachWidgetView(entry: entry)
}
.configurationDisplayName("Beach Events")
.description("Events at the beach")
.associatedKind(WidgetKinds.beachEventsTimeline)
}
} Create a Preview with relevanceEntries
#Preview("Entries") {
BeachEventWidget()
} relevanceEntries: {
BeachEventRelevanceEntry.previewShorebirds
BeachEventRelevanceEntry.previewMeditation
} Create a Preview with relevance
#Preview("Provider and Relevance") {
BeachEventWidget()
} relevanceProvider: {
BeachEventRelevanceProvider(store: .preview)
} relevance: {
let configurations: [BeachEventConfigurationIntent] = [
.previewSurfing,
.previewMeditation,
.previewWalk
]
let attributes = configurations.map {
WidgetRelevanceAttribute(
configuration: $0,
context: .date($0.event.startDate, kind: .default)
)
}
return WidgetRelevance(attributes)
} Create a Preview with a relevanceProvider
#Preview("Provider") {
BeachEventWidget()
} relevanceProvider: {
BeachEventRelevanceProvider(store: .preview)
} Resources
Related sessions
-
20 min -
15 min -
18 min -
27 min -
24 min -
11 min -
24 min