Streaming is available in most browsers,
and in the Developer app.
-
Bring your Live Activity to Apple Watch
Bring Live Activities into the Smart Stack on Apple Watch with iOS 18 and watchOS 11. We'll cover how Live Activities are presented on Apple Watch, as well as how you can enhance their presentation for the Smart Stack. We'll also explore additional considerations to ensure Live Activities on Apple Watch always present up-to-date information.
Chapters
- 0:00 - Introduction
- 1:07 - Review your Live Activity
- 3:22 - Customize for Apple Watch
- 6:02 - Keep it live
Resources
-
Download
Hi, I'm Anne, and I’m a Frameworks engineer working on watchOS. I’m delighted to show you how to deliver a great experience on Apple Watch for your existing iOS Live Activity.
Live Activities provide a way for you to show up-to-date information about an activity or event from your app in glanceable locations like the Lock Screen, in StandBy, and in the Dynamic Island.
Now, in iOS 18 and watchOS 11, your iOS Live Activity will appear in the Smart Stack on Apple Watch automatically.
I’ll start by talking about how your Live Activity appears on Apple Watch after updating to watchOS 11.
Then I’ll show you how you can customize your Live Activity view for the SmartStack. And I’ll fill you in on some details about Activity updates for watchOS and how to keep your Live Activity up-to-date.
Let’s get started by reviewing how your existing iOS Live Activity appears on Apple Watch in watchOS 11.
When people leave the Lock Screen on iPhone with a Dynamic Island, your Live Activity shifts to showing the compact leading and trailing views in the Dynamic Island. The views in the Dynamic Island come from the “compact leading” and “compact trailing” view builders. On Apple Watch, these same views are automatically shown in the Smart Stack, along with a title indicating that they were provided by your app. This is a great opportunity for you to consider whether your compact views are making the best use of the space available to keep people up to date. Here, my app is showing the estimated time until my delivery in the leading view, and the current status of my order in the trailing view.
Updates to your Live Activity on iOS are automatically sent to Apple Watch. On iOS, alerting updates animate to display your Dynamic Island Expanded Views. When the alerting update is received on Apple Watch, if it’s currently at the watch face, the system automatically launches the Smart Stack, displays your alert, and then shows your Live Activity.
If an app is in the foreground, a banner is displayed at the bottom of the screen with your Dynamic Island compact views.
Tapping a Live Activity shows a full-screen presentation with an option to open the app on iPhone.
The Dynamic Island compact views for your iOS Live Activity will appear in the Smart Stack automatically. Review your current views to ensure that you’re showing dynamically-updating information to keep people informed about the state of the activity. This will benefit people who have updated to iOS 18 and watchOS 11, and your existing iPhone customers.
So far, I’ve talked about what will happen automatically when people update to iOS 18 and watchOS 11. You also have an opportunity to provide a custom Live Activity view for Apple Watch. My app lets people order local produce to their door, and see the status of their deliveries using a Live Activity. Let’s modify it to customize the Live Activity view for Apple Watch.
Currently my Live Activity uses the default presentation in the Smart Stack and shows the compact Dynamic Island views. I can see how that will appear in Xcode using a Preview.
In the Canvas Device Settings, I can see all the View Styles in the Canvas together by selecting All Variants. Or I can go to Select mode and update the Canvas Device Settings to show the Content Smart Stack to focus on my Smart Stack view.
To customize for the watchOS Smart Stack, I’ll add the supplementalActivityFamilies modifier to the WidgetConfiguration for my Live Activity. I’ll use .small to indicate support for the Smart Stack. Now my iOS Lock Screen View from my activity content is displayed in the Smart Stack instead of the compact views. Since I designed my lock screen content for a larger view, the text is being truncated on Apple Watch. I’m going to customize this for the Smart Stack.
I’ll get the activityFamily Environment value. Then provide a new layout for my content when the activityFamily is small.
When the activity family is medium, for the iOS Lock Screen, I’ll use my original content view layout.
I can preview how my view will appear in the Smart Stack using the Xcode Preview for my Live Activity.
By adding the supplementalActivityFamilies modifier, my Live Activity now provides a custom view when presented on Apple Watch.
Live Activities work on Apple Watch even if you don’t have a Watch App. But if you do have a Watch App, you can also opt-in to open it from a tap on the Live Activity in the Smart Stack.
In the Build Settings for your Watch app target, add a value for the Supports Launch for Live Activity Attribute Types key in the Info.plist section. To launch your Watch app for all your Live Activities, leave the value empty. To launch for only specific Live Activities, add an item for each ActivityAttributes conforming type that should launch the Watch app.
With just a few lines of code, I’ve been able to update how my Live Activity appears, and I’ve been able to preview how this will be displayed. On Apple Watch, there are a few additional things you should know to make sure your Live Activity is showing the most up-to-date information possible and works just how you intended.
I’ll cover update frequency and budgeting, handling limited connectivity, and adapting your Live Activity view for Always On Display.
There are a few differences in the update frequency and budget between iPhone and Apple Watch.
Live Activity updates are synchronized automatically to Apple Watch. You don't have to manage separate push tokens or add any code. To protect battery life, update synchronization is budgeted. The budget threshold is similar to iOS. If you use push updates for your Live Activity today, they should be within the budget for Apple Watch with no extra work. Apple Watch also supports high-frequency updates when requested.
In your iOS app, consider cases where your Live Activity is updated locally with ActivityKit. Now, these updates also synchronize to Apple Watch, and count against its update budget. If an update is over budget, it may not immediately appear when someone’s wrist is down. However, when they raise their wrist, the Live Activity will show the latest information available.
Connection state is another reason your activity might not receive timely updates on Apple Watch. When your Watch has a good connection to its nearby companion iPhone or is on the same Wi-Fi network, updates are generally sent to Apple Watch. With limited connectivity, Start, End, and alerting updates are prioritized for Apple Watch.
The system helps people know that they may not be seeing current information by showing a last connected message in the Smart Stack. Also consider adjustments your activity view may need for Always On Display. When the watch is in Always On mode, the system will automatically switch the Color Scheme to dark and set reduced luminance when someone puts their wrist down.
If you have brightly-colored views, use the isLuminanceReduced Environment value to remove bright elements or reduce their brightness.
In my view, I’m using a different tint for the gauge when the luminance is reduced to reduce the brightness and preserve readability.
If you want your Live Activity to have a light appearance, set the preferredColorScheme to light. It will automatically use the dark appearance in Always On Display with reduced luminance. Semantic colors, like primary, will automatically use an appropriate color for the color scheme. Now my activity will look great and show the best information possible at all times.
Beginning in iOS 18 and watchOS 11, your iOS Live Activity will appear in the Smart Stack on Apple Watch automatically. Ensure your Dynamic Island Compact Views are timely, relevant, and informative.
Use supplementalActivityFamilies to customize your Live Activity for Apple Watch. For more information about great Live Activity design, check out the video “Design Live Activities for Apple Watch”. For those of you who haven’t developed for watchOS before, Live Activities may be your first foray into customizing your app content for watchOS. We’re so happy to have you join us on this platform and we hope you’ll explore further to bring your apps to Apple Watch. Thank you.
-
-
1:28 - Existing Live Activity views
struct DeliveryLiveActivity: Widget { var body: some WidgetConfiguration { ActivityConfiguration( for: DeliveryActivityAttributes.self ) { context in DeliveryActivityContent(context: context) } dynamicIsland: { context in DynamicIsland { DynamicIslandExpandedRegion(.leading) { DeliveryExpandedLeadingView(context: context) } DynamicIslandExpandedRegion(.trailing) { DeliveryExpandedTrailingView(context: context) } DynamicIslandExpandedRegion(.bottom) { DeliveryExpandedBottomView(context: context) } } compactLeading: { DeliveryCompactLeading(context: context) } compactTrailing: { DeliveryCompactTrailing(context: context) } minimal: { DeliveryMinimal(context: context) } } } }
-
3:43 - Preview Live Activities with Xcode Previews
extension DeliveryActivityAttributes.ContentState { static var shippedOrder: DeliveryActivityAttributes.ContentState { .init( status: .shipped, courierName: "Johnny" ) } static var packedOrder: DeliveryActivityAttributes.ContentState { .init( status: .packed, courierName: "Contacting Courier...") } } #Preview( "Dynamic Island Compact", as: .dynamicIsland(.compact), using: DeliveryActivityAttributes.preview ) { DeliveryLiveActivity() } contentStates: { DeliveryActivityAttributes.ContentState.packedOrder DeliveryActivityAttributes.ContentState.shippedOrder }
-
4:15 - Add .supplementalActivityFamilies to indicate support for the Smart Stack
struct DeliveryLiveActivity: Widget { var body: some WidgetConfiguration { ActivityConfiguration( for: DeliveryActivityAttributes.self ) { context in DeliveryActivityContent(context: context) } dynamicIsland: { context in DynamicIsland { DynamicIslandExpandedRegion(.leading) { DeliveryExpandedLeadingView(context: context) } DynamicIslandExpandedRegion(.trailing) { DeliveryExpandedTrailingView(context: context) } DynamicIslandExpandedRegion(.bottom) { DeliveryExpandedBottomView(context: context) } } compactLeading: { DeliveryCompactLeading(context: context) } compactTrailing: { DeliveryCompactTrailing(context: context) } minimal: { DeliveryMinimal(context: context) } } .supplementalActivityFamilies([.small]) } }
-
4:49 - Customize view layout for the small activity family
struct DeliveryActivityContent: View { @Environment(\.activityFamily) var activityFamily var context: ActivityViewContext<DeliveryActivityAttributes> var body: some View { switch activityFamily { case .small: DeliverySmallContent(context: context) case .medium: DeliveryMediumContent(context: context) @unknown default: DeliveryMediumContent(context: context) } } }
-
5:06 - Preview customized layouts for the Smart Stack
#Preview("Content", as: .content, using: DeliveryActivityAttributes.preview) { DeliveryLiveActivity() } contentStates: { DeliveryActivityAttributes.ContentState.packedOrder DeliveryActivityAttributes.ContentState.shippedOrder }
-
8:37 - Use isLuminanceReduced to remove bright elements with Always On Display
struct DeliveryGauge: View { @Environment(\.isLuminanceReduced) private var isLuminanceReduced var context: ActivityViewContext<DeliveryActivityAttributes> var body: some View { Gauge(value: context.state.progressPercent) { GaugeLabel(context: context) } .tint(isLuminanceReduced ? .gaugeDim : .gauge) } }
-
8:57 - For Live Activities with a light appearance, use a light preferredColorScheme
struct DeliveryActivityContent: View { @Environment(\.activityFamily) var activityFamily var context: ActivityViewContext<DeliveryActivityAttributes> var body: some View { switch activityFamily { case .small: DeliverySmallContent(context: context) .preferredColorScheme(.light) case .medium: DeliveryMediumContent(context: context) @unknown default: DeliveryMediumContent(context: context) } } }
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.