{"$schema": "https://raw.githubusercontent.com/guitaripod/wwdc-sessions/master/schema/transcript.schema.json", "id": "wwdc2026-223", "language": "eng", "source": "https://developer.apple.com/videos/play/wwdc2026/223", "wordCount": 2205, "segments": [{"start": 7.0, "text": "Hi, I'm Adi, and I'm a System Experience Engineer."}, {"start": 10.0, "text": "Today, I'll cover the essentials for building Live Activities"}, {"start": 13.0, "text": "and how to make them shine on every screen."}, {"start": 16.0, "text": "I'll start with an overview of the experience that Live Activities offer,"}, {"start": 20.0, "text": "and I'll go into how your app can create them"}, {"start": 23.0, "text": "and keep them up-to-date."}, {"start": 25.0, "text": "Then, I'll touch on how you can further optimize them for your app."}, {"start": 30.0, "text": "Live Activities are a great way for apps to provide timely"}, {"start": 34.0, "text": "and glanceable updates for something that's happening right now -"}, {"start": 38.0, "text": "like this one, from the MLB app."}, {"start": 40.0, "text": "It keeps track of someone's favorite teams"}, {"start": 42.0, "text": "and shows a Live Activity when they're playing."}, {"start": 45.0, "text": "People stay up-to-date with the score, the current inning, and key game updates,"}, {"start": 49.0, "text": "right from the Lock Screen,"}, {"start": 52.0, "text": "And on the Home Screen or when using apps,"}, {"start": 54.0, "text": "they appear right in the Dynamic Island, so people never miss a thing."}, {"start": 60.0, "text": "Live Activities can also expand"}, {"start": 62.0, "text": "to show more information from the Dynamic Island."}, {"start": 65.0, "text": "This occurs when an alerting update happens"}, {"start": 67.0, "text": "or when someone long-presses on it."}, {"start": 70.0, "text": "The expanded view provides even more space"}, {"start": 73.0, "text": "to let people know about essential updates."}, {"start": 76.0, "text": "And in iOS 27, Live Activities are visible in the Dynamic Island,"}, {"start": 81.0, "text": "when in portrait and landscape."}, {"start": 85.0, "text": "They also appear in other places too,"}, {"start": 88.0, "text": "like in StandBy, when iPhone is in landscape and charging."}, {"start": 92.0, "text": "When your app runs a Live Activity on iPhone,"}, {"start": 95.0, "text": "it automatically appears on other Apple devices."}, {"start": 98.0, "text": "Including right on Apple Watch, in the Smart Stack."}, {"start": 102.0, "text": "In the macOS menu bar or right on the CarPlay Dashboard."}, {"start": 106.0, "text": "This makes it super easy for people to glance at the key information"}, {"start": 110.0, "text": "they need from your app, no matter where they are."}, {"start": 114.0, "text": "To bring Live Activities to your app, I'll cover how they get created,"}, {"start": 118.0, "text": "and how your app keeps them up-to-date."}, {"start": 121.0, "text": "It starts by planning your data model"}, {"start": 123.0, "text": "so that your Live Activity's updates can be fast and efficient."}, {"start": 128.0, "text": "Then, create the basic views in each of its key presentations."}, {"start": 133.0, "text": "Finally, I'll provide updates, either from the app when it's running"}, {"start": 137.0, "text": "or through push notifications in the background."}, {"start": 141.0, "text": "I'll start with the data model."}, {"start": 143.0, "text": "To explore how to do this,"}, {"start": 145.0, "text": "I'll add a Live Activity to an app that I'm working on."}, {"start": 149.0, "text": "It lets me order coffee from a local coffee shop."}, {"start": 152.0, "text": "I can pick my favorite drink and customize it, just the way I like it."}, {"start": 156.0, "text": "When I'm done, I send my order to the store for pickup."}, {"start": 161.0, "text": "The first step to building a Live Activity is to come up with a great design."}, {"start": 167.0, "text": "They're meant to provide immediate, glanceable information."}, {"start": 170.0, "text": "You'll want to craft a design"}, {"start": 172.0, "text": "that prioritizes the key things people need to know over time."}, {"start": 176.0, "text": "For inspiration,"}, {"start": 178.0, "text": "check out the Human Interface Guidelines for help designing your Live Activity"}, {"start": 182.0, "text": "and check out the session, \"Design dynamic Live Activities\"."}, {"start": 186.0, "text": "For this app, I'll use my initial designs for the Lock Screen"}, {"start": 190.0, "text": "to start planning the data model."}, {"start": 192.0, "text": "It will have different presentations for when the order is placed,"}, {"start": 195.0, "text": "when it's being worked on, when it's ready for pickup,"}, {"start": 199.0, "text": "and a brief opportunity to leave feedback after I'm done."}, {"start": 202.0, "text": "I'll need to consider which parts of the data are static,"}, {"start": 205.0, "text": "and which parts of the data are dynamic."}, {"start": 208.0, "text": "That's because Live Activities treat static and dynamic data differently"}, {"start": 212.0, "text": "in order to provide efficient updates."}, {"start": 214.0, "text": "Only the dynamic data can be updated during the lifetime of a Live Activity."}, {"start": 220.0, "text": "Data that never changes will be contained in a struct,"}, {"start": 223.0, "text": "that conforms to the ActivityAttributes protocol."}, {"start": 226.0, "text": "Values that do change over time, are part of a separate ContentState struct."}, {"start": 231.0, "text": "In the coffee order, there are a few things that are static and won't change."}, {"start": 235.0, "text": "An order always stays with the same coffee shop,"}, {"start": 238.0, "text": "so the name of the shop is static."}, {"start": 241.0, "text": "The drink that someone orders also won't change"}, {"start": 244.0, "text": "but the status of the order, as well as the remaining time, are dynamic."}, {"start": 248.0, "text": "The app will update those values over time."}, {"start": 252.0, "text": "To create a data model for this Live Activity,"}, {"start": 255.0, "text": "I'll import ActivityKit and create a DrinkOrderAttributes struct"}, {"start": 260.0, "text": "conforming to ActivityAttributes."}, {"start": 263.0, "text": "Then, I'll add properties for all of the static data:"}, {"start": 267.0, "text": "the name of the shop, the drink for the order,"}, {"start": 269.0, "text": "and a unique identifier that my server uses to track each order."}, {"start": 275.0, "text": "Then, I'll add a ContentState struct containing the dynamic data."}, {"start": 281.0, "text": "This includes the order's phase,"}, {"start": 283.0, "text": "like whether it's being prepared, or ready for pickup,"}, {"start": 286.0, "text": "as well as the estimated ready time, and the rating left for the order."}, {"start": 292.0, "text": "And that's it!"}, {"start": 294.0, "text": "Now that I have the data model in place, I'll build the views for the Live Activity."}, {"start": 300.0, "text": "The interface for a Live Activity is built using WidgetKit."}, {"start": 304.0, "text": "To get started,"}, {"start": 305.0, "text": "add a widget extension to your app, if you don't already have one."}, {"start": 309.0, "text": "There, you'll provide an ActivityConfiguration"}, {"start": 312.0, "text": "that describes its views."}, {"start": 314.0, "text": "Each presentation of Live Activity is a SwiftUI view,"}, {"start": 318.0, "text": "which reads the attributes and content state provided to it."}, {"start": 322.0, "text": "If you're new to SwiftUI, check out the video \"SwiftUI essentials\"."}, {"start": 327.0, "text": "For the drink order,"}, {"start": 328.0, "text": "I'll start by creating an ActivityConfiguration"}, {"start": 331.0, "text": "in my widget extension."}, {"start": 333.0, "text": "By specifying the DrinkOrderAttributes type,"}, {"start": 337.0, "text": "these views will be associated with the right Live Activity."}, {"start": 342.0, "text": "The content closure provides the SwiftUI view that should appear."}, {"start": 347.0, "text": "In this case, I've a view called ActivityView."}, {"start": 350.0, "text": "To show the right values, like whether the coffee is being prepared"}, {"start": 354.0, "text": "or ready, it uses the context parameter."}, {"start": 358.0, "text": "The context contains the attributes"}, {"start": 360.0, "text": "and the most recent content state that should be rendered."}, {"start": 364.0, "text": "Next, I'll provide views for the Dynamic Island."}, {"start": 369.0, "text": "The first three are: compactLeading, compactTrailing, and minimal views."}, {"start": 374.0, "text": "These views are small and appear when someone isn't actively interacting with it."}, {"start": 380.0, "text": "Carefully consider which information is essential"}, {"start": 383.0, "text": "from the larger presentation to appear in these views."}, {"start": 387.0, "text": "For the coffee order,"}, {"start": 388.0, "text": "the leading view shows a symbol for the type of drink I ordered,"}, {"start": 392.0, "text": "while the trailing view has a label for the order's phase."}, {"start": 396.0, "text": "I'll also provide the minimal view."}, {"start": 398.0, "text": "This view may appear when multiple Live Activities are running."}, {"start": 403.0, "text": "Minimal views should provide the most essential information"}, {"start": 406.0, "text": "that someone will glance at."}, {"start": 407.0, "text": "For this order, it provides a circular gauge showing the time remaining."}, {"start": 413.0, "text": "Finally, I'll build up the expanded view in the Dynamic Island."}, {"start": 418.0, "text": "This view is much larger and can accommodate more information,"}, {"start": 421.0, "text": "similar to the Lock Screen view."}, {"start": 424.0, "text": "It consists of multiple regions that surround the sensors on iPhone."}, {"start": 428.0, "text": "In each closure, I'll provide a view"}, {"start": 431.0, "text": "for each of the regions I need in a DynamicIslandExpandedRegion block."}, {"start": 437.0, "text": "Now that the data model and views are built,"}, {"start": 439.0, "text": "it's time to start the Live Activity and keep it up-to-date."}, {"start": 443.0, "text": "Live Activities can be started in a few different ways."}, {"start": 447.0, "text": "Using the ActivityKit framework,"}, {"start": 449.0, "text": "you can start one directly any time your app is running in the foreground"}, {"start": 453.0, "text": "or a Live Activity can be scheduled to start in advance at a specific time."}, {"start": 458.0, "text": "Alternatively, you can also start it from a push notification."}, {"start": 463.0, "text": "The simplest way is to use ActivityKit."}, {"start": 466.0, "text": "For my app, I'll start by checking if Live Activities are authorized."}, {"start": 471.0, "text": "Then, I'll create an instance of the DrinkOrderAttributes struct for the order."}, {"start": 476.0, "text": "I'll fill in the static data,"}, {"start": 478.0, "text": "like the coffee shop name and the drink ordered."}, {"start": 482.0, "text": "Then, I'll construct the contentState,"}, {"start": 484.0, "text": "which contains the initial values for the dynamic data of this Live Activity."}, {"start": 490.0, "text": "I'll set the first phase of the order, the ordered phase,"}, {"start": 494.0, "text": "and most drinks are ready in 15 minutes... so"}, {"start": 497.0, "text": "I'll set an initial ready time of 15 minutes from now."}, {"start": 502.0, "text": "The contentState of a Live Activity also has a staleDate."}, {"start": 506.0, "text": "A staleDate lets you specify when this content should be considered out-of-date."}, {"start": 511.0, "text": "When the content is stale, your Live Activity views can indicate that."}, {"start": 515.0, "text": "For now, I won't set a staleDate for a coffee order."}, {"start": 520.0, "text": "Then, I'll request the system start a Live Activity"}, {"start": 523.0, "text": "using the attributes and content I've defined."}, {"start": 527.0, "text": "While the Live Activity is running, it's just as easy to update."}, {"start": 531.0, "text": "Call the .update method on the activity with a new ContentState,"}, {"start": 535.0, "text": "as well as a new staleDate."}, {"start": 537.0, "text": "Live Activities can also be updated with push notifications."}, {"start": 541.0, "text": "There are two strategies to choose from."}, {"start": 544.0, "text": "First, you can broadcast updates."}, {"start": 547.0, "text": "This is a great choice when you have hundreds,"}, {"start": 549.0, "text": "thousands or more people running the same Live Activity at the same time."}, {"start": 554.0, "text": "With this strategy,"}, {"start": 556.0, "text": "your server sends updates to everyone using a broadcast channel."}, {"start": 560.0, "text": "Then, you configure the Live Activity to subscribe to that channel"}, {"start": 564.0, "text": "for its updates."}, {"start": 566.0, "text": "The other strategy, is to use push notifications."}, {"start": 569.0, "text": "This is great for all other use cases."}, {"start": 572.0, "text": "The server can send push notifications to target updates to specific devices."}, {"start": 577.0, "text": "For this strategy,"}, {"start": 579.0, "text": "you'll obtain a push token for the Live Activity"}, {"start": 582.0, "text": "and use that to send each update."}, {"start": 585.0, "text": "To learn more, the documentation has a great guide"}, {"start": 588.0, "text": "on how to use ActivityKit push notifications."}, {"start": 591.0, "text": "So far, I've covered just the first steps with Live Activities."}, {"start": 596.0, "text": "Next, I'll share how to go even further to optimize them."}, {"start": 601.0, "text": "I'll discuss adding more customized presentations"}, {"start": 604.0, "text": "and bringing interactivity to the views."}, {"start": 608.0, "text": "I'll start with further refining their presentations."}, {"start": 612.0, "text": "In iOS 27,"}, {"start": 613.0, "text": "the Dynamic Island compact and minimal views"}, {"start": 616.0, "text": "are visible in both portrait and landscape."}, {"start": 619.0, "text": "In portrait, compact views are flexible in width"}, {"start": 623.0, "text": "but in landscape, they don't have room to grow in width."}, {"start": 626.0, "text": "Your Live Activity"}, {"start": 627.0, "text": "needs to account for when the Dynamic Island is constrained in width"}, {"start": 630.0, "text": "like this."}, {"start": 632.0, "text": "Here's the implementation of the CompactTrailingView for the coffee order."}, {"start": 636.0, "text": "It's a SwiftUI view that either shows the estimated time for the drink order,"}, {"start": 641.0, "text": "if there's one available,"}, {"start": 643.0, "text": "or it shows the label for the order's phase,"}, {"start": 646.0, "text": "like the string \"Ready\"."}, {"start": 649.0, "text": "I'll start by adding the environment value isDynamicIslandLimitedInWidth,"}, {"start": 655.0, "text": "then I'll adjust the View body."}, {"start": 658.0, "text": "When the Dynamic Island is limited in width,"}, {"start": 660.0, "text": "I'll display an alternate trailing view"}, {"start": 662.0, "text": "that shows an icon of the order's progress instead."}, {"start": 666.0, "text": "Now, the new trailing view fits nicely into the limited width."}, {"start": 672.0, "text": "Another presentation to consider is StandBy,"}, {"start": 674.0, "text": "which can appear when iPhone is charging in landscape."}, {"start": 679.0, "text": "In this presentation, the Lock Screen view is used,"}, {"start": 682.0, "text": "scaled up to 200%."}, {"start": 685.0, "text": "The gradient background that works great on Lock Screen"}, {"start": 688.0, "text": "makes the activity feel small and doesn't fill the screen,"}, {"start": 691.0, "text": "leaving a lot of blank space."}, {"start": 694.0, "text": "To fix this,"}, {"start": 695.0, "text": "I'll adjust how my Live Activity's view displays its background."}, {"start": 699.0, "text": "I'll add the showsWidgetContainerBackground @Environment value to the view."}, {"start": 704.0, "text": "This value is true on the Lock Screen, so there,"}, {"start": 708.0, "text": "I'll apply my gradient .background."}, {"start": 710.0, "text": "Next, I'll use the .activityBackgroundTint on the View"}, {"start": 714.0, "text": "to set a recognizable background color otherwise."}, {"start": 719.0, "text": "Now, the Live Activity"}, {"start": 720.0, "text": "presents an edge-to-edge background tint color in StandBy."}, {"start": 725.0, "text": "Live Activities also appear in the Smart Stack on Apple Watch"}, {"start": 729.0, "text": "and in CarPlay."}, {"start": 731.0, "text": "To customize them for these places,"}, {"start": 733.0, "text": "just add support for the small device family."}, {"start": 737.0, "text": "Live Activities are automatically forwarded from iPhone to CarPlay"}, {"start": 741.0, "text": "and use my ActivityView by default."}, {"start": 744.0, "text": "This view looks great on Lock Screen"}, {"start": 746.0, "text": "but doesn't fit well in the space."}, {"start": 749.0, "text": "To adapt for this layout,"}, {"start": 751.0, "text": "first declare support for the small activity family."}, {"start": 755.0, "text": "This indicates to the system that your views are adapted to this smaller format."}, {"start": 761.0, "text": "Then, add the activityFamily @Environment value to the View"}, {"start": 765.0, "text": "and provide a customized view for this presentation"}, {"start": 768.0, "text": "when the value of activityFamily is .small."}, {"start": 772.0, "text": "Now the Live Activity looks great everywhere!!"}, {"start": 776.0, "text": "People love being able to get access to your app's glanceable information"}, {"start": 780.0, "text": "while on-the-go."}, {"start": 782.0, "text": "To learn even more about adapting views for the small activity family,"}, {"start": 786.0, "text": "check out the session, \"Bring your Live Activity to Apple Watch\"."}, {"start": 791.0, "text": "Live Activities can be a great opportunity"}, {"start": 793.0, "text": "for people to take quick, immediate actions."}, {"start": 796.0, "text": "You can provide this by adding interactivity."}, {"start": 799.0, "text": "When an order is complete in the coffee app,"}, {"start": 802.0, "text": "I want to make it easy for people to rate their order."}, {"start": 805.0, "text": "To do this,"}, {"start": 807.0, "text": "each button in the Live Activity is associated with an App Intent."}, {"start": 811.0, "text": "When someone taps a button, the system executes the associated intent."}, {"start": 817.0, "text": "In the implementation, the RateDrinkIntent conforms to LiveActivityIntent,"}, {"start": 823.0, "text": "and it takes two parameters, the ID for the order"}, {"start": 826.0, "text": "and a boolean describing whether the rating was positive or not."}, {"start": 831.0, "text": "The perform method is where the app's logic is implemented."}, {"start": 835.0, "text": "When either button is tapped, this function will run."}, {"start": 839.0, "text": "The app can implement this method to do all of the work involved,"}, {"start": 842.0, "text": "like sharing this rating back with the server"}, {"start": 844.0, "text": "and updating the database."}, {"start": 847.0, "text": "Finally, I'll update the ratings Button View,"}, {"start": 850.0, "text": "which is used in both my ActivityView and DynamicIslandExpandedRegion."}, {"start": 856.0, "text": "I'll add two buttons for each intent,"}, {"start": 858.0, "text": "and can create a RateDrinkIntent for each action."}, {"start": 863.0, "text": "Live Activities are a great way to keep people updated"}, {"start": 866.0, "text": "about things they care about that are happening in real time."}, {"start": 870.0, "text": "Now you're empowered to get started with them in your apps."}, {"start": 874.0, "text": "Some next steps are -"}, {"start": 876.0, "text": "build Live Activities with the ActivityKit and WidgetKit frameworks;"}, {"start": 880.0, "text": "use attributes and content state"}, {"start": 882.0, "text": "to model your static and dynamic data for efficient updates;"}, {"start": 886.0, "text": "create outstanding presentations on the Lock Screen,"}, {"start": 890.0, "text": "in the Dynamic Island, and more;"}, {"start": 893.0, "text": "use ActivityKit and push notifications for timely updates to its data;"}, {"start": 898.0, "text": "And curate each experience, like in landscape,"}, {"start": 902.0, "text": "in StandBy, on Apple Watch, and others."}, {"start": 906.0, "text": "Thanks for watching!"}]}