{"$schema": "https://raw.githubusercontent.com/guitaripod/wwdc-sessions/master/schema/transcript.schema.json", "id": "wwdc2026-278", "language": "eng", "source": "https://developer.apple.com/videos/play/wwdc2026/278", "wordCount": 2429, "segments": [{"start": 6.0, "text": "Hi, I'm Michael Ochs, an engineering manager on the UI Frameworks team."}, {"start": 11.0, "text": "And today I'll tell you how to modernize your UIKit app."}, {"start": 15.0, "text": "In this video I'll tell you about some big changes to app adaptivity requirements,"}, {"start": 20.0, "text": "and how iPhone apps are fully resizable."}, {"start": 24.0, "text": "Next, I'll present some new APIs in tab bars, navigation bars and menus."}, {"start": 30.0, "text": "Then, I'll talk about how to support Apple Intelligence"}, {"start": 34.0, "text": "and some changes you should be aware of."}, {"start": 38.0, "text": "And finally I'll cover a new skill that helps an agent to handle"}, {"start": 42.0, "text": "most of this modernization work automatically."}, {"start": 46.0, "text": "Let's get started with app adaptivity."}, {"start": 49.0, "text": "Your app can already appear in many different environments."}, {"start": 52.0, "text": "There are different screen sizes, and apps can run side by side -"}, {"start": 55.0, "text": "with other apps and even themselves."}, {"start": 58.0, "text": "On iPad, people expect apps to resize and move to external displays seamlessly."}, {"start": 64.0, "text": "On iPhone, people expect apps to work in both portrait and landscape orientations."}, {"start": 69.0, "text": "They also expect to mirror their iPhone to the Mac."}, {"start": 73.0, "text": "In iOS and macOS 27 this experience has been improved"}, {"start": 76.0, "text": "and apps running in these environments are now exposed"}, {"start": 79.0, "text": "to many of the dynamic changes any app native to the platform needs to support."}, {"start": 85.0, "text": "When people use iPhone Mirroring on the Mac, they can fully resize the iPhone window,"}, {"start": 90.0, "text": "allowing your apps to resize and adapt."}, {"start": 92.0, "text": "Likewise, an iPhone-only app running on iPad will be fully resizable"}, {"start": 97.0, "text": "like any other iPad app."}, {"start": 99.0, "text": "Because of this, it is important that your app dynamically adjusts"}, {"start": 103.0, "text": "to any available scene size at runtime."}, {"start": 106.0, "text": "If your app is a universal binary, you are off to a great start."}, {"start": 110.0, "text": "But there is more to do to make your app fully adaptive and have it dynamically"}, {"start": 114.0, "text": "adjust to the environment it is running in."}, {"start": 117.0, "text": "I will cover the most important steps and common issues you might encounter"}, {"start": 121.0, "text": "when making your app more adaptive:"}, {"start": 124.0, "text": "verifying your app is no longer using app lifecycle,"}, {"start": 127.0, "text": "and instead has adopted scene lifecycle, the basis for any adaptive app,"}, {"start": 132.0, "text": "making sure your app is not using main screen references,"}, {"start": 136.0, "text": "and how to handle user interface idiom and interface orientation checks."}, {"start": 142.0, "text": "The first step is to move from app lifecycle to scene lifecycle."}, {"start": 147.0, "text": "Most apps are already using scene lifecycle."}, {"start": 150.0, "text": "It is the basis for an adaptive app and for many of the other tasks"}, {"start": 153.0, "text": "I'm going to show you in this video."}, {"start": 156.0, "text": "UIScene lifecycle is now required when building with the latest SDKs."}, {"start": 161.0, "text": "Without it, your application will no longer launch."}, {"start": 164.0, "text": "Verify that your app is using a UISceneDelegate"}, {"start": 167.0, "text": "which is the basis for scene lifecycle."}, {"start": 170.0, "text": "If you have not yet migrated to scene lifecycle, check out the video"}, {"start": 173.0, "text": "\"Make your UIKit app more flexible\" from WWDC25"}, {"start": 177.0, "text": "and read \"Transitioning to the UIKit scene-based lifecycle\""}, {"start": 180.0, "text": "in the documentation."}, {"start": 182.0, "text": "Next, when your iPhone app is mirrored on a Mac,"}, {"start": 185.0, "text": "or when a person moves your app to an external display on the iPad,"}, {"start": 189.0, "text": "the screen associated with your scene changes."}, {"start": 192.0, "text": "That means that any reference to the main screen in your code will provide"}, {"start": 196.0, "text": "incorrect information for the environment your app is running in."}, {"start": 200.0, "text": "It is important that you do not reference the main screen in your app."}, {"start": 204.0, "text": "Instead, access the screen dynamically from a window's window scene."}, {"start": 209.0, "text": "When a view or view controller is not available in the immediate context,"}, {"start": 212.0, "text": "pass in a screen reference to any method that needs it."}, {"start": 216.0, "text": "Even better than fetching the correct screen is to remove screen references all together."}, {"start": 222.0, "text": "There are a lot of other APIs that are better suited for an adaptive app."}, {"start": 225.0, "text": "I'll take you through two common patterns."}, {"start": 229.0, "text": "Accessing the scale of the screen should be replaced"}, {"start": 232.0, "text": "with the trait collection's displayScale."}, {"start": 235.0, "text": "Views and view controllers automatically update their trait collections"}, {"start": 238.0, "text": "and provide reasonable fallbacks"}, {"start": 240.0, "text": "even when they are not part of the visible hierarchy."}, {"start": 243.0, "text": "A lot of common override points are also tracked,"}, {"start": 246.0, "text": "meaning that you do not need to explicitly monitor for changes."}, {"start": 250.0, "text": "Instead, the system tracks which trait collection properties are being used"}, {"start": 254.0, "text": "inside common layout and drawing methods, like layoutSubviews, updateProperties,"}, {"start": 260.0, "text": "drawRect, and many others."}, {"start": 262.0, "text": "If a change to a tracked trait is detected, the system will ensure these methods"}, {"start": 267.0, "text": "are called again so your UI automatically updates accordingly."}, {"start": 270.0, "text": "Check out \"Automatic trait tracking\" in the documentation to learn more."}, {"start": 275.0, "text": "In places where automatic trait tracking is not available, registerForTraitChanges"}, {"start": 279.0, "text": "can be used to observe changes."}, {"start": 282.0, "text": "This method allows you to set up a closure that is called when a specific trait"}, {"start": 286.0, "text": "in the receiving view changes."}, {"start": 289.0, "text": "Use this to invalidate caches or update other data related to that view."}, {"start": 294.0, "text": "Check out \"Adapting your app when traits change\""}, {"start": 297.0, "text": "in the documentation to learn more."}, {"start": 300.0, "text": "Another common use of the screen is to check its bounds to get"}, {"start": 303.0, "text": "the amount of space available to your app."}, {"start": 306.0, "text": "However, in an adaptive environment, the space your scene has available"}, {"start": 310.0, "text": "is not always the full screen."}, {"start": 313.0, "text": "So if you still have any references to screen bounds in your app,"}, {"start": 316.0, "text": "now is the time to remove these."}, {"start": 319.0, "text": "The window scene's effective geometry provides information on how much space"}, {"start": 323.0, "text": "your app has available."}, {"start": 325.0, "text": "If you need to monitor the effective geometry for changes, implement"}, {"start": 329.0, "text": "windowScene:didUpdateEffectiveGeometry: in your scene delegate."}, {"start": 334.0, "text": "In your views and view controllers, instead of referencing the scene bounds,"}, {"start": 338.0, "text": "use the available size of your view controller's view or your view's superview"}, {"start": 343.0, "text": "to determine how much space is available to it."}, {"start": 346.0, "text": "This makes your UI less dependent on how it is presented."}, {"start": 350.0, "text": "It will adjust better when your view controller appears in other contexts,"}, {"start": 354.0, "text": "for example inside of a split view controller."}, {"start": 357.0, "text": "For games, resizing can be challenging."}, {"start": 360.0, "text": "Due to this, UIRequiresFullscreen is honored on iPhone in resizable"}, {"start": 364.0, "text": "environments starting in iOS 27."}, {"start": 367.0, "text": "Its behavior has also been updated"}, {"start": 369.0, "text": "and no longer opts your app fully out of resizing."}, {"start": 372.0, "text": "Instead, it enables discrete resizing that honors"}, {"start": 376.0, "text": "your supported interface orientations."}, {"start": 379.0, "text": "In discrete resizing, every time a person changes the scene size,"}, {"start": 383.0, "text": "the system transitions the scene to a new screen configuration"}, {"start": 386.0, "text": "matching that size,"}, {"start": 388.0, "text": "so your game always renders at full quality in the available space."}, {"start": 392.0, "text": "If your app is using the User Interface idiom trait,"}, {"start": 396.0, "text": "be aware that this trait is no longer meaningful for any kind of layout decision."}, {"start": 401.0, "text": "Your app is expected to use the additional space in a meaningful way,"}, {"start": 405.0, "text": "regardless of whether it is running in the phone or pad user interface idiom."}, {"start": 410.0, "text": "When your iPhone app is running on an iPad or in iPhone Mirroring on the Mac,"}, {"start": 414.0, "text": "it will be fully resizable,"}, {"start": 416.0, "text": "but it will still run under the phone user interface idiom."}, {"start": 419.0, "text": "Stop checking the user interface idiom for any layout decisions in your code."}, {"start": 424.0, "text": "Use size classes instead to handle sizing constraints, such as collapsing menus"}, {"start": 429.0, "text": "and updating your app's layout for the available space."}, {"start": 432.0, "text": "If you need finer control, use the surrounding view's size"}, {"start": 435.0, "text": "like I mentioned earlier."}, {"start": 437.0, "text": "Interface orientation also is no longer useful for layout decisions."}, {"start": 442.0, "text": "In iOS 27, an app's supported interface orientation"}, {"start": 446.0, "text": "is a preference provided to the system."}, {"start": 448.0, "text": "It will be ignored when your app is running in a resizable environment."}, {"start": 452.0, "text": "You should not consider interface orientation for any layout calculations."}, {"start": 457.0, "text": "In iPhone Mirroring on the Mac, your apps will always be running"}, {"start": 460.0, "text": "in the portrait interface orientation,"}, {"start": 462.0, "text": "regardless of the aspect ratio of your app's scene."}, {"start": 465.0, "text": "Any interface orientation checks in your app should also be updated to use size classes."}, {"start": 471.0, "text": "This conceptual shift was introduced in iOS 8."}, {"start": 475.0, "text": "At WWDC2014, Bruce Nilo said:"}, {"start": 479.0, "text": "\"A device rotation is only an animated bounds change.\""}, {"start": 483.0, "text": "With an array of device sizes, resizable windows on iPad,"}, {"start": 487.0, "text": "and resizable iPhone apps on Mac,"}, {"start": 489.0, "text": "today this insight is more relevant than ever."}, {"start": 492.0, "text": "And speaking of interface orientation: in iOS 27 UIView also conforms to the new"}, {"start": 498.0, "text": "Body protocols from CoreMotion and CoreLocation."}, {"start": 501.0, "text": "This makes it much easier to configure your motion and location managers."}, {"start": 506.0, "text": "Connect them to the view that visualizes the motion data,"}, {"start": 509.0, "text": "such as a compass or a map view."}, {"start": 511.0, "text": "This ensures the data is always in the right coordinate space,"}, {"start": 514.0, "text": "regardless of interface orientation."}, {"start": 517.0, "text": "That covers the main adaptivity changes."}, {"start": 520.0, "text": "Now here is how to test these changes in your app."}, {"start": 524.0, "text": "Xcode 27 brings new ways to iterate on your app's behavior"}, {"start": 528.0, "text": "across different screen sizes,"}, {"start": 530.0, "text": "without having to install your app on multiple separate simulators or devices."}, {"start": 536.0, "text": "In the new Device Hub app as well as in Xcode Previews,"}, {"start": 539.0, "text": "click the \"enter resize mode\" icon."}, {"start": 542.0, "text": "Then, drag the edges of the device to resize it freely."}, {"start": 546.0, "text": "This allows you to iterate on your changes quicker."}, {"start": 549.0, "text": "Once you are satisfied with the results, make sure to test iPhone Mirroring"}, {"start": 553.0, "text": "and iPad with real devices."}, {"start": 556.0, "text": "To learn more about the Device Hub app and its tools,"}, {"start": 559.0, "text": "watch \"Get the most out of Device Hub\"."}, {"start": 562.0, "text": "And that's adaptivity."}, {"start": 564.0, "text": "Before I show you a new agentic coding skill that can help you with the work"}, {"start": 568.0, "text": "necessary to make your app fully adaptive, there are two more topics to cover."}, {"start": 573.0, "text": "First up: bars and menus."}, {"start": 576.0, "text": "On iPad, tab bars can expand into a full sidebar representation"}, {"start": 579.0, "text": "to surface more sections of the app hierarchy"}, {"start": 582.0, "text": "when the current environment supports a sidebar."}, {"start": 585.0, "text": "On iPhone, the bottom tab bar is shown across all sizes by default."}, {"start": 591.0, "text": "New in iOS 27, iPhone apps can also opt into sidebars by setting"}, {"start": 596.0, "text": "the tab bar controller's sidebar.preferredPlacement to .sidebar."}, {"start": 601.0, "text": "Note that in contrast to the iPad, this is an app choice."}, {"start": 605.0, "text": "If your app opts into the sidebar representation, there is no way to toggle"}, {"start": 609.0, "text": "between a sidebar and tab bar layout in the UI."}, {"start": 612.0, "text": "Instead, the system determines if there is enough space to show a sidebar,"}, {"start": 617.0, "text": "for example when the horizontal size class is regular."}, {"start": 622.0, "text": "To determine if the tab bar's sidebar representation can be shown,"}, {"start": 625.0, "text": "use the sidebar's isAvailable property."}, {"start": 628.0, "text": "If a sidebar is not currently available, surface the UI behind nested tabs"}, {"start": 633.0, "text": "in other parts of your app."}, {"start": 635.0, "text": "To learn more about managing tab groups,"}, {"start": 637.0, "text": "watch \"Make your UIKit app more flexible\" from WWDC25,"}, {"start": 641.0, "text": "and to learn more about tab bars and its integration with sidebars,"}, {"start": 645.0, "text": "watch \"Elevate your tab and sidebar experience in iPadOS\" from WWDC24."}, {"start": 653.0, "text": "UITabBarController also lets you customize the prominent tab."}, {"start": 657.0, "text": "The prominent tab is always visible,"}, {"start": 660.0, "text": "even when the tab bar collapses during scrolling."}, {"start": 663.0, "text": "In iOS 27, you have the option to make any tab prominent"}, {"start": 666.0, "text": "by setting the prominentTabIdentifier."}, {"start": 669.0, "text": "Okay, that's tab bars. Now let's talk about navigation bars."}, {"start": 675.0, "text": "Navigation bars can interactively slide away as people scroll."}, {"start": 679.0, "text": "This provides more room on the screen for your app's content."}, {"start": 684.0, "text": "By default, navigation bars minimize in certain conditions defined by the system."}, {"start": 690.0, "text": "You can force this behavior, one way or the other,"}, {"start": 692.0, "text": "by setting the barMinimizationBehavior property"}, {"start": 695.0, "text": "on your navigation item to .always or .never."}, {"start": 698.0, "text": "If you handle safe area avoidance yourself,"}, {"start": 701.0, "text": "set barMinimizationSafeAreaAdjustment to .never so bar minimization doesn't update"}, {"start": 707.0, "text": "insets automatically."}, {"start": 710.0, "text": "Another change during scroll interactions is an updated appearance"}, {"start": 713.0, "text": "for the scroll edge effects."}, {"start": 715.0, "text": "As such, you should review your design,"}, {"start": 717.0, "text": "especially where you have previously overridden"}, {"start": 720.0, "text": "the defaults provided by the OS."}, {"start": 723.0, "text": "In particular, the .automatic style no longer switches between"}, {"start": 726.0, "text": "the existing soft and hard styles"}, {"start": 728.0, "text": "but provides its own visuals for additional clarity."}, {"start": 732.0, "text": "If you have overridden the style from .automatic previously,"}, {"start": 735.0, "text": "that decision should be re-evaluated,"}, {"start": 737.0, "text": "especially when set to .soft, as that no longer matches"}, {"start": 741.0, "text": "the default system appearance."}, {"start": 744.0, "text": "With the refined look of Liquid Glass,"}, {"start": 746.0, "text": "images you set on menu elements"}, {"start": 748.0, "text": "may not be shown by default in some contexts,"}, {"start": 751.0, "text": "such as in the menu bars on iPadOS and macOS."}, {"start": 755.0, "text": "If you still need an image to be visible, set the preferredImageVisibility property"}, {"start": 759.0, "text": "to override the default system behavior."}, {"start": 763.0, "text": "Review the updated Human Interface Guidelines"}, {"start": 765.0, "text": "for when to include visible images in a menu element."}, {"start": 769.0, "text": "And that's bars and menus."}, {"start": 771.0, "text": "Now, how to support Apple Intelligence in your app."}, {"start": 776.0, "text": "Menus in iOS 27 feature an Ask Siri button,"}, {"start": 780.0, "text": "to allow people to start a conversation with Siri right from your app."}, {"start": 784.0, "text": "This is a powerful entry point that allows people to interact"}, {"start": 787.0, "text": "with the context they care about."}, {"start": 791.0, "text": "Menus will automatically display this item when there's content relevant for Siri."}, {"start": 796.0, "text": "To provide more relevant information specific to your app,"}, {"start": 799.0, "text": "use the new View Annotations API."}, {"start": 802.0, "text": "With it you can annotate specific views with AppEntities."}, {"start": 806.0, "text": "Check out"}, {"start": 807.0, "text": "\"Explore advanced App Intents features for Siri and Apple Intelligence\""}, {"start": 811.0, "text": "to learn more."}, {"start": 814.0, "text": "If your app supports drag and drop, Siri can load resources"}, {"start": 817.0, "text": "from your application's drag handlers."}, {"start": 820.0, "text": "When Apple Intelligence is invoked from context menus, the system will call"}, {"start": 824.0, "text": "available drag delegate methods to load the content."}, {"start": 828.0, "text": "Avoid performing animations or presenting modal UI from sessionWillBegin."}, {"start": 834.0, "text": "Drag sessions can be initiated without a user gesture."}, {"start": 837.0, "text": "If your app has a stateful UI that shows up when a user initiates a drag,"}, {"start": 842.0, "text": "put that code in sessionDidMove instead."}, {"start": 845.0, "text": "If the adaptivity changes I outlined sound like a lot of work, I've got you covered."}, {"start": 851.0, "text": "Let's talk about what's on everyone's mind: agentic coding!"}, {"start": 856.0, "text": "New in Xcode 27 is an app modernization skill."}, {"start": 859.0, "text": "It has a deep understanding of the adaptivity tasks I outlined."}, {"start": 863.0, "text": "And with the context of your project,"}, {"start": 866.0, "text": "it can make a lot of these changes automatically."}, {"start": 869.0, "text": "Use Xcode's intelligence features and ask an agent to make your app more adaptable."}, {"start": 875.0, "text": "It will automatically convert main screen calls to traitCollection"}, {"start": 879.0, "text": "or scene bounds checks,"}, {"start": 881.0, "text": "adding invalidation logic if necessary."}, {"start": 885.0, "text": "It will also replace interface orientation checks with size class checks."}, {"start": 889.0, "text": "It will even convert your app to use scene lifecycle."}, {"start": 893.0, "text": "For more complex tasks, it will ask clarifying questions."}, {"start": 897.0, "text": "And for tasks too large to handle in a single session,"}, {"start": 900.0, "text": "it will add comments to help you keep track"}, {"start": 902.0, "text": "of the remaining work."}, {"start": 905.0, "text": "And to use skills in other tools, you can export the ones Xcode uses with"}, {"start": 910.0, "text": "\"xcrun agent skills export\"."}, {"start": 913.0, "text": "This will create markdown files that you can then import in your workflows."}, {"start": 918.0, "text": "Skills like this one are a powerful way to prepare your app"}, {"start": 922.0, "text": "for resizable environments."}, {"start": 925.0, "text": "And… that's it!"}, {"start": 926.0, "text": "These are the most important things to modernize your app."}, {"start": 930.0, "text": "Build your app with the iOS 27 SDK, and try out the resizable simulator"}, {"start": 934.0, "text": "in the new Device Hub app"}, {"start": 936.0, "text": "and test your app in iPhone Mirroring on macOS 27."}, {"start": 940.0, "text": "Identify areas in your app that need to be a little more flexible."}, {"start": 944.0, "text": "And if you like agentic coding, give the new skill a try"}, {"start": 947.0, "text": "and discover how much it can do automatically."}, {"start": 951.0, "text": "Thanks for joining."}, {"start": 952.0, "text": "I cannot wait to resize your apps."}]}