{"$schema": "https://raw.githubusercontent.com/guitaripod/wwdc-sessions/master/schema/transcript.schema.json", "id": "wwdc2026-277", "language": "eng", "source": "https://developer.apple.com/videos/play/wwdc2026/277", "wordCount": 3270, "segments": [{"start": 7.0, "text": "Hi, my name is Jonathan Long and I'm an engineer on the system experience team."}, {"start": 13.0, "text": "People love using widgets."}, {"start": 15.0, "text": "Your widgets provide relevant content in the convenient places people visit most."}, {"start": 20.0, "text": "Widgets are available on many Apple platforms"}, {"start": 22.0, "text": "including iOS, iPadOS, watchOS, visionOS, and macOS."}, {"start": 28.0, "text": "Your widgets extend the reach of your app across the system"}, {"start": 32.0, "text": "providing another opportunity for people to experience your great apps."}, {"start": 36.0, "text": "So let's dive into widgets and discuss the foundations of widget kit,"}, {"start": 40.0, "text": "how to build your first widget, and how to keep it up to date."}, {"start": 44.0, "text": "Today, I will cover Widget fundamentals and building your first widget."}, {"start": 48.0, "text": "What WidgetKit offers to better integrate your app and widget experience."}, {"start": 53.0, "text": "And how to ensure your widgets adapt when the system environment changes,"}, {"start": 56.0, "text": "like to a tinted environment."}, {"start": 59.0, "text": "First, fundamentals, beginning with what are widgets?"}, {"start": 63.0, "text": "There are three qualities that make widgets memorable."}, {"start": 66.0, "text": "Widgets are glanceable."}, {"start": 68.0, "text": "People should be able to understand your widgets with a quick glance."}, {"start": 72.0, "text": "For example, weather shows me just enough information about the current forecast"}, {"start": 76.0, "text": "to help me get ready for my day."}, {"start": 79.0, "text": "Widgets are relevant."}, {"start": 80.0, "text": "Widgets content should match expectations for time, personal patterns, and location."}, {"start": 86.0, "text": "The calendar widget shows me the next events at the current time and updates"}, {"start": 90.0, "text": "throughout the day."}, {"start": 92.0, "text": "Widgets are personalizable;"}, {"start": 94.0, "text": "able to be configured with the content that matters to me,"}, {"start": 97.0, "text": "like this photos memory widget showing me a great memory at a family camp"}, {"start": 101.0, "text": "with my daughters."}, {"start": 103.0, "text": "Using WidgetKit and SwiftUI you can provide great glanceable, relevant,"}, {"start": 108.0, "text": "and personalizable widgets for your apps content."}, {"start": 112.0, "text": "I have been building an app for my book club to encourage me to read more."}, {"start": 115.0, "text": "The app lets me track how much I have read, the books I have completed,"}, {"start": 119.0, "text": "and creates a schedule to help me complete a book before my next book club meeting."}, {"start": 123.0, "text": "I also created some widgets so I can view this data right from my home screen."}, {"start": 128.0, "text": "The first widget is the reading goals widget"}, {"start": 130.0, "text": "encouraging me to read throughout the day."}, {"start": 134.0, "text": "The second, the reading log widget,"}, {"start": 136.0, "text": "helps me keep track of my current progress through a book."}, {"start": 139.0, "text": "The third widget builds a schedule for me to follow so I can finish my book on time."}, {"start": 144.0, "text": "Throughout this talk I'll cover key decisions for each widget"}, {"start": 147.0, "text": "that can help when creating your widgets."}, {"start": 150.0, "text": "I'll start by covering how an app provides widgets to the system."}, {"start": 154.0, "text": "Whether an app is built with SwiftUI or UIKit, it can have widgets,"}, {"start": 158.0, "text": "and the widgets will be built with SwiftUI."}, {"start": 161.0, "text": "Your app provides widgets to the system from a widget extension."}, {"start": 165.0, "text": "This extension runs as a separate process from your app."}, {"start": 170.0, "text": "Because your widget extension is running as a separate process,"}, {"start": 173.0, "text": "you will need to use a shared container"}, {"start": 175.0, "text": "in an app group to provide data from your app to your widget extension."}, {"start": 179.0, "text": "You can use something like a shared database or user defaults."}, {"start": 183.0, "text": "The widget extension is solely focused on the widget."}, {"start": 187.0, "text": "The system and widget kit interact with the extension"}, {"start": 189.0, "text": "to get the data needed for widgets."}, {"start": 192.0, "text": "WidgetKit asks the extension for content."}, {"start": 195.0, "text": "This content is called a timeline."}, {"start": 198.0, "text": "A timeline is made up of multiple timeline entries."}, {"start": 202.0, "text": "WidgetKit provides these entries as data for the widgets view."}, {"start": 206.0, "text": "The resulting views are archived."}, {"start": 208.0, "text": "The system displays them at their relevant time."}, {"start": 212.0, "text": "WidgetExtensions expose your widgets to the system"}, {"start": 215.0, "text": "and provide their timeline content."}, {"start": 218.0, "text": "Timelines are a series of entries, each carrying the data needed to"}, {"start": 221.0, "text": "render your widget's view at a specific point in time."}, {"start": 225.0, "text": "Now let's look at the code for the reading goals widget"}, {"start": 227.0, "text": "that brings these pieces together."}, {"start": 230.0, "text": "When you create a new target for your widget extension,"}, {"start": 233.0, "text": "Xcode generates a widget for you."}, {"start": 236.0, "text": "For a simple widget this implementation already has a lot of what we need."}, {"start": 240.0, "text": "Starting with a body providing a WidgetConfiguration."}, {"start": 244.0, "text": "There are two types of configurations for widgets:"}, {"start": 247.0, "text": "AppIntentConfigurations and StaticConfigurations."}, {"start": 251.0, "text": "AppIntentConfigurations are used when your widget can be configured by the user."}, {"start": 257.0, "text": "My widget will be automatically configured using the current book I am reading,"}, {"start": 261.0, "text": "so I am using the static configuration which is the most simple."}, {"start": 265.0, "text": "The static configuration needs a few parameters."}, {"start": 267.0, "text": "The kind, which is a unique identifier for this specific type of widget."}, {"start": 273.0, "text": "A timeline provider that produces timeline entries for the widget."}, {"start": 277.0, "text": "And a closure that takes a timeline entry and returns a View."}, {"start": 282.0, "text": "From the closure you return a SwiftUI view for the provided timeline entry."}, {"start": 287.0, "text": "Because my book club app is built in SwiftUI, I already have a view,"}, {"start": 291.0, "text": "the DailyReadingGoalView, that is exactly what I need for my widget."}, {"start": 296.0, "text": "To specify the background, I am using the containerBackground modifier."}, {"start": 300.0, "text": "This modifier identifies which view is the background of my widget."}, {"start": 306.0, "text": "When people using my widget customize their devices with a colored or clear tint,"}, {"start": 311.0, "text": "this allows the system to replace the background view specified"}, {"start": 314.0, "text": "with a glass material view."}, {"start": 316.0, "text": "The view portion of the Reading Goal widget is implemented."}, {"start": 320.0, "text": "Let's have a closer look at what is expected of the timeline provider"}, {"start": 323.0, "text": "and how timelines keep widgets relevant."}, {"start": 326.0, "text": "The TimelineProvider supplies entries"}, {"start": 328.0, "text": "to represent three separate states for my widget:"}, {"start": 332.0, "text": "Snapshots, Placeholder, and Timeline."}, {"start": 337.0, "text": "A snapshot is a realistic preview of a widget."}, {"start": 340.0, "text": "It's what people see in the widget gallery."}, {"start": 343.0, "text": "This is an opportunity for my widget to make a strong first impression."}, {"start": 347.0, "text": "My app has no data before someone starts using it, so I feature a popular book,"}, {"start": 352.0, "text": "Atomic Habits, with a default message."}, {"start": 355.0, "text": "So people can imagine my widget at its best"}, {"start": 357.0, "text": "before they ever add it to their Home Screen."}, {"start": 360.0, "text": "A placeholder is a stand-in view the system shows when your widget"}, {"start": 364.0, "text": "doesn't have content to display yet,"}, {"start": 366.0, "text": "like the very first time it's loading your timeline."}, {"start": 369.0, "text": "Because it needs to show up instantly, fetching a placeholder has to be synchronous."}, {"start": 373.0, "text": "So provide a placeholder that does not need data from disk or over the network."}, {"start": 379.0, "text": "For the Reading Goals widget, I'm using SwiftUI's redacted modifier,"}, {"start": 383.0, "text": "which creates a simplified version of my View."}, {"start": 388.0, "text": "A timeline entry is what your widget shows at a specific moment in time."}, {"start": 392.0, "text": "That could be right now, or any point in the future."}, {"start": 396.0, "text": "Your timeline provider produces a collection of these entries,"}, {"start": 399.0, "text": "and the system renders each one at its specific time."}, {"start": 404.0, "text": "The timeline entry for the reading goals widget has all the information the widget"}, {"start": 407.0, "text": "needs to render this view."}, {"start": 409.0, "text": "The motivational message, pages read, title, and cover name."}, {"start": 416.0, "text": "Most of this data will be the same for this widget"}, {"start": 418.0, "text": "except for the motivational message."}, {"start": 421.0, "text": "The message updates at various times throughout the day."}, {"start": 424.0, "text": "As I begin discussing the timelines, I'm going to only show the message"}, {"start": 428.0, "text": "that will be changing over time."}, {"start": 430.0, "text": "Timelines are critical to how widgets stay up to date."}, {"start": 434.0, "text": "Each timeline entry provides the needed data to render a widget view."}, {"start": 438.0, "text": "This timeline is currently showing two entries,"}, {"start": 441.0, "text": "one at 9am and one at 11:30am."}, {"start": 446.0, "text": "The core piece of data my reading goals widget needs"}, {"start": 448.0, "text": "is the motivational message that updates throughout the day"}, {"start": 451.0, "text": "as widget kit advances the timeline."}, {"start": 456.0, "text": "These timeline entries are provided to my widget to produce the relevant view"}, {"start": 461.0, "text": "for that entry at the specific time,"}, {"start": 463.0, "text": "keeping my widget relevant with fresh content."}, {"start": 467.0, "text": "At some point your timeline will need to be refreshed with more timeline entries."}, {"start": 472.0, "text": "This is referred to as reloading a timeline."}, {"start": 475.0, "text": "Timelines specify their reload behavior through a reload policy."}, {"start": 480.0, "text": "The reload policy can be one of three options:"}, {"start": 482.0, "text": "atEnd, afterDate, and never."}, {"start": 486.0, "text": "Let's discuss each policy and when it makes sense to choose which one."}, {"start": 491.0, "text": "The atEnd policy indicates that the timeline should be reloaded"}, {"start": 495.0, "text": "when all timeline entries have been exhausted."}, {"start": 499.0, "text": "Throughout the day new timeline entries will be rendered."}, {"start": 503.0, "text": "When the last entry has been shown at 1:00pm, the system issues a reload,"}, {"start": 508.0, "text": "asking your widget extension for more content."}, {"start": 512.0, "text": "Your widget extension will provide a new timeline with more timeline entries."}, {"start": 517.0, "text": "The reading goals widget updates its motivational message at varied times"}, {"start": 521.0, "text": "throughout the day."}, {"start": 522.0, "text": "The atEnd policy makes sense because this widget provides a series of entries"}, {"start": 527.0, "text": "where the end is not a single known time"}, {"start": 529.0, "text": "and needs to be reloaded when the timeline is exhausted."}, {"start": 533.0, "text": "The afterDate policy allows you to specify a specific date your widget"}, {"start": 537.0, "text": "desires a reload."}, {"start": 539.0, "text": "These are different timeline entries powering the reading schedule widget."}, {"start": 543.0, "text": "I have redacted the complete set of data and only include the chapter information"}, {"start": 547.0, "text": "that changes over time."}, {"start": 548.0, "text": "Here the reading schedule widget provides two timeline entries indicating what needs"}, {"start": 553.0, "text": "to be read today and tomorrow."}, {"start": 556.0, "text": "The widget needs to be reloaded at the end of the day"}, {"start": 558.0, "text": "to recalculate the downstream schedule."}, {"start": 561.0, "text": "It uses the afterDate reload policy specifying a date at the end of the day."}, {"start": 567.0, "text": "Once the current time reaches this date, my extension is reloaded"}, {"start": 571.0, "text": "and asked for a new timeline."}, {"start": 574.0, "text": "The new timeline provides entries for Tuesday and Wednesday"}, {"start": 577.0, "text": "with the recalculated schedule."}, {"start": 579.0, "text": "The afterDate policy is great in cases like the reading schedule widget"}, {"start": 583.0, "text": "when there is a specific time you know your widget will need to be reloaded."}, {"start": 589.0, "text": "And lastly, the never reload policy."}, {"start": 592.0, "text": "As the name suggests, your widget won't reload on its own."}, {"start": 596.0, "text": "Use this when automatic reloads don't make sense."}, {"start": 599.0, "text": "The Reading Log widget is a good example."}, {"start": 601.0, "text": "It only needs to refresh when someone interacts with the app or widget."}, {"start": 606.0, "text": "When you do need to reload, you can do this with an explicit call"}, {"start": 609.0, "text": "to WidgetCenter's reload APIs"}, {"start": 611.0, "text": "or by sending a push notification."}, {"start": 614.0, "text": "To dig deeper into reload policies,"}, {"start": 616.0, "text": "check out \"Principles of great widgets\" from WWDC21."}, {"start": 621.0, "text": "There are a few best practices to keep in mind"}, {"start": 623.0, "text": "when considering building and reloading your timeline."}, {"start": 627.0, "text": "Provide multiple timeline entries whenever possible."}, {"start": 631.0, "text": "This ensures the system always has content to show for your widget."}, {"start": 635.0, "text": "WidgetKit was built with all day battery life in mind."}, {"start": 638.0, "text": "So each widget is given a budget for updates."}, {"start": 642.0, "text": "The budget is heavily influenced by users viewing habits"}, {"start": 645.0, "text": "and is updated throughout the day."}, {"start": 647.0, "text": "Frequency of updates can vary and the system is smart enough"}, {"start": 650.0, "text": "to adapt reloads for your widget as it makes sense."}, {"start": 654.0, "text": "Know that frequent reloads while your app is in the foreground might be throttled."}, {"start": 659.0, "text": "If your widget data may have changed a final call to reload when your app enters"}, {"start": 663.0, "text": "the background is usually a good idea."}, {"start": 666.0, "text": "Some content is ephemeral with a defined start and end date,"}, {"start": 669.0, "text": "needs more frequent updates,"}, {"start": 671.0, "text": "and wants alerting capabilities, like a sporting event."}, {"start": 674.0, "text": "If this describes your content, consider building a live activity."}, {"start": 678.0, "text": "You can learn more about Live Activities in \"Live Activities essentials\""}, {"start": 682.0, "text": "from WWDC 26."}, {"start": 685.0, "text": "So far, all my widgets have been the same size — the system medium family."}, {"start": 691.0, "text": "But now that my WidgetExtension and timeline provider are wired up,"}, {"start": 694.0, "text": "a whole lineup of other widget families are available to me."}, {"start": 699.0, "text": "Widgets come in all different shapes and sizes."}, {"start": 702.0, "text": "It is recommended to support as many sizes as you can"}, {"start": 705.0, "text": "so that people using your widget have choices when placing their widgets."}, {"start": 711.0, "text": "The system extra large portrait family was introduced in visionOS 26."}, {"start": 716.0, "text": "New in macOS, iOS, and iPadOS 27,"}, {"start": 719.0, "text": "the system extra large portrait family is now available."}, {"start": 723.0, "text": "This new family allows people using your widgets"}, {"start": 726.0, "text": "to have a really good look at your apps content."}, {"start": 729.0, "text": "The Book Club reading schedule can reuse the same data from the medium widget"}, {"start": 732.0, "text": "we have already implemented."}, {"start": 734.0, "text": "This larger size allows me to see how far along"}, {"start": 736.0, "text": "I should be in the next couple of days."}, {"start": 740.0, "text": "Not all widget families make sense for your widget,"}, {"start": 742.0, "text": "and starting with a few families is most simple."}, {"start": 746.0, "text": "Here is my daily reading goal widget I am building."}, {"start": 748.0, "text": "I can use the .supportedFamilies modifier,"}, {"start": 751.0, "text": "listing all the widget families my widget supports."}, {"start": 755.0, "text": "When adding a new widget family,"}, {"start": 756.0, "text": "I can reuse the same widget and timeline provider,"}, {"start": 759.0, "text": "and build a swiftUI view that makes sense for the new families shape and size."}, {"start": 764.0, "text": "I just covered the basic steps you need to build your first widget."}, {"start": 768.0, "text": "Build a widget with a widget extension that is focused on your widget."}, {"start": 772.0, "text": "You provide content to your widget through a timeline made up of timeline entries."}, {"start": 777.0, "text": "Choose a timeline reload policy that makes sense for your use case."}, {"start": 782.0, "text": "My app now has a great iOS widget to keep me on track for book club."}, {"start": 786.0, "text": "And my widget is actually available in other places as well."}, {"start": 790.0, "text": "My iOS widget is available on CarPlay and as a remote widget on macOS."}, {"start": 795.0, "text": "We just discussed what you need to do to build a widget."}, {"start": 798.0, "text": "Now let's discuss some additional options WidgetKit provides to better integrate"}, {"start": 802.0, "text": "your apps content with your widget."}, {"start": 805.0, "text": "You can better integrate your widget with your app by using Deep links,"}, {"start": 810.0, "text": "making your widgets configurable,"}, {"start": 812.0, "text": "and by adding interactive elements to your widgets."}, {"start": 816.0, "text": "The default interaction for your widget is to open your app,"}, {"start": 819.0, "text": "which is a great starting point."}, {"start": 821.0, "text": "If your widget is showing specific content from within your app,"}, {"start": 825.0, "text": "your widget can provide a deep link directly to that content."}, {"start": 829.0, "text": "Let's jump back into the Reading Goals Widget code"}, {"start": 831.0, "text": "and see how to do this."}, {"start": 833.0, "text": "The reading goals widget shows the current book I am reading."}, {"start": 837.0, "text": "I will provide a deep link to the book's details page so tapping the widget lands"}, {"start": 841.0, "text": "people where they expect."}, {"start": 844.0, "text": "I will use the widgetURL modifier specifying a deep link URL for my app"}, {"start": 849.0, "text": "to handle on launch."}, {"start": 851.0, "text": "The URL encodes the book's ID, so the app launches directly"}, {"start": 855.0, "text": "to the book's details page."}, {"start": 858.0, "text": "Deep links are a great way to integrate your widget with your app,"}, {"start": 862.0, "text": "keeping people in context as they move between them."}, {"start": 865.0, "text": "Configurable widgets are another great way to integrate your widget with your app."}, {"start": 870.0, "text": "Making your widget configurable lets people personalize their widget"}, {"start": 874.0, "text": "with specific content from your app."}, {"start": 877.0, "text": "The weather widget is a great example."}, {"start": 879.0, "text": "People can configure this widget to show conditions"}, {"start": 882.0, "text": "from a location that is important to them."}, {"start": 884.0, "text": "I like to keep track of the weather in Yosemite,"}, {"start": 886.0, "text": "just in case I can plan a spur of the moment trip."}, {"start": 890.0, "text": "The reading log widget in my book club app is another example of a configurable widget."}, {"start": 895.0, "text": "People using my app can configure this widget to track"}, {"start": 897.0, "text": "reading sessions for a specific book."}, {"start": 900.0, "text": "Configurable widgets can be configured from wherever they are placed,"}, {"start": 903.0, "text": "like from the iOS home screen."}, {"start": 906.0, "text": "This is the configuration UI for my reading log widget"}, {"start": 909.0, "text": "which only has one parameter."}, {"start": 911.0, "text": "The UI allows people using my widget to select the book they want to track."}, {"start": 915.0, "text": "I made the most recently read book the default"}, {"start": 918.0, "text": "so people don't need to make a selection."}, {"start": 920.0, "text": "Configurable widgets also let people add"}, {"start": 922.0, "text": "multiple widgets with different configurations."}, {"start": 925.0, "text": "Here my home screen has three reading log widgets"}, {"start": 928.0, "text": "tracking the three different books I am reading."}, {"start": 931.0, "text": "When you're thinking about configurable widgets,"}, {"start": 933.0, "text": "there are a few things to keep in mind."}, {"start": 936.0, "text": "Consider whether your widget's content should change depending on who's using it."}, {"start": 940.0, "text": "Keep configuration fast — one or two parameters is usually all you need."}, {"start": 945.0, "text": "And don't require configuration up front, provide sensible defaults"}, {"start": 949.0, "text": "that people can tweak later if they want to."}, {"start": 952.0, "text": "To learn more about making your widget configurable with App Intents, check out"}, {"start": 956.0, "text": "\"Explore enhancements to App Intents\" from WWDC23."}, {"start": 961.0, "text": "Configurable widgets give people using your widget options to make their devices"}, {"start": 965.0, "text": "relevant and personal for them."}, {"start": 968.0, "text": "Your widget can also integrate with your app through interactive elements."}, {"start": 972.0, "text": "Buttons and toggles let people perform actions directly from the widget."}, {"start": 977.0, "text": "Reminders is a great example of an interactive widget."}, {"start": 980.0, "text": "Once I have completed a task, I can check it off right from the widget."}, {"start": 984.0, "text": "Receiving the dopamine hit I need to keep moving through my day."}, {"start": 988.0, "text": "When you're thinking about interactive elements,"}, {"start": 990.0, "text": "here are a few things to keep in mind."}, {"start": 993.0, "text": "Widgets can surface interactive elements as either a toggle or a button."}, {"start": 997.0, "text": "Think about the most important action in your app and expose it from your widget,"}, {"start": 1001.0, "text": "like the complete chapter button on the reading log widget."}, {"start": 1005.0, "text": "Widget views are archived and rendered by the system, so your code isn't running"}, {"start": 1009.0, "text": "while the widget is on screen."}, {"start": 1011.0, "text": "Buttons and toggles take an App Intent that the system can execute on your behalf"}, {"start": 1015.0, "text": "when someone interacts with the element."}, {"start": 1018.0, "text": "To learn more about interactive widgets,"}, {"start": 1020.0, "text": "check out \"Bring widgets to life\" from WWDC23."}, {"start": 1024.0, "text": "Your widget is an extension of your app."}, {"start": 1027.0, "text": "Deep links, configurable widgets, and interactive elements are all great ways"}, {"start": 1031.0, "text": "to unify the experience between your app and widget."}, {"start": 1035.0, "text": "People using your widget can also customize their system experience."}, {"start": 1039.0, "text": "Widgets were designed to adapt to these system changes."}, {"start": 1043.0, "text": "On iOS, the system can be customized to be tinted with a specific color"}, {"start": 1047.0, "text": "or to have a clear tint."}, {"start": 1049.0, "text": "With either customization, the system renders your widget through a glass material,"}, {"start": 1053.0, "text": "tinting your content and replacing your background with an adaptive glass effect."}, {"start": 1057.0, "text": "This keeps every widget on the Home Screen feeling cohesive."}, {"start": 1061.0, "text": "SwiftUI does a lot of the heavy lifting here, but it is important to test"}, {"start": 1065.0, "text": "your widget to make sure it looks great."}, {"start": 1069.0, "text": "As I begin testing my reading goals widget, I can see that it is looking"}, {"start": 1073.0, "text": "really great when rendered in full color."}, {"start": 1075.0, "text": "Before I'm done, I want to test with a tinted customization to make sure"}, {"start": 1079.0, "text": "my widget is rendering as expected."}, {"start": 1082.0, "text": "I'll do this by running on device and customizing my home screen."}, {"start": 1087.0, "text": "When I change my iPhone to use the clear mode, my widget isn't rendering correctly."}, {"start": 1092.0, "text": "The book cover is a large white rectangle, which is not the intended behavior."}, {"start": 1097.0, "text": "This is my BookCoverImage view."}, {"start": 1099.0, "text": "In the view's body the image is rendered for this specific book"}, {"start": 1102.0, "text": "from the asset catalog."}, {"start": 1104.0, "text": "When rendering in the accented rendering mode the system is unable"}, {"start": 1107.0, "text": "to accent the image appropriately."}, {"start": 1110.0, "text": "I can specify the rendering mode to be used for this image"}, {"start": 1113.0, "text": "with the widgetAccentedRenderingMode modifier."}, {"start": 1116.0, "text": "With this option my widget now renders the book cover using full color."}, {"start": 1121.0, "text": "I am using the full color option so the book covers are rendered"}, {"start": 1124.0, "text": "respecting their original colors."}, {"start": 1126.0, "text": "With this change my widget is looking great in the accented rendering mode."}, {"start": 1131.0, "text": "It's important to test your widget in every environment they appear."}, {"start": 1134.0, "text": "Start with your local devices."}, {"start": 1136.0, "text": "Try your widgets in full color, tinted,"}, {"start": 1139.0, "text": "and clear mode to make sure they render as expected."}, {"start": 1142.0, "text": "Remember that your iOS widgets also show up on macOS as remote widgets."}, {"start": 1147.0, "text": "Take the time to test that your interactions still feel right"}, {"start": 1150.0, "text": "when someone's using them from a Mac."}, {"start": 1153.0, "text": "Lean on SwiftUI previews to iterate quickly."}, {"start": 1157.0, "text": "In the swiftUI canvas on the right side of Xcode you can check different families,"}, {"start": 1161.0, "text": "color schemes, and rendering modes without ever leaving Xcode."}, {"start": 1166.0, "text": "Turn on WidgetKit developer mode while you're testing"}, {"start": 1169.0, "text": "to lift constraints like reload budgets."}, {"start": 1171.0, "text": "This allows you to iterate on your widgets more quickly."}, {"start": 1175.0, "text": "To learn more about adapting your widget to these system customizations,"}, {"start": 1179.0, "text": "check out \"What's new in widgets\" from WWDC25."}, {"start": 1184.0, "text": "I covered a lot today."}, {"start": 1186.0, "text": "Before I let you go, keep these things in mind."}, {"start": 1189.0, "text": "I hope you are inspired to go and build a great widget!"}, {"start": 1193.0, "text": "Consider how you can extend and personalize your widget experience"}, {"start": 1196.0, "text": "by integrating with your app."}, {"start": 1199.0, "text": "And be sure to test and adapt your widget to all the custom environments"}, {"start": 1202.0, "text": "that each platform provides."}, {"start": 1205.0, "text": "Widgets make my iPhone fun and personal to me!"}, {"start": 1208.0, "text": "I can't wait to use the great widgets you create!"}]}