WWDC.ai

Modernize your UIKit app

Update UIKit apps for iOS 27 resizable iPhone environments, scene lifecycle, adaptive layout APIs, modern bars, Apple Intelligence, and Xcode agent skills.

Watch on Apple Developer

TL;DR

  • iOS 27 makes iPhone apps fully resizable in iPhone Mirroring and on iPad, so UIKit apps must adapt to any scene size at runtime.
  • UIScene lifecycle is required when building with the latest SDKs; audit legacy app lifecycle, UIScreen.main, userInterfaceIdiom, and interfaceOrientation usage.
  • UIKit adds APIs for iPhone sidebar placement, prominent tabs, navigation bar minimization, menu image visibility, and view-based motion/location coordinate spaces.
  • Apple Intelligence can use context menus, View Annotations, and drag handlers; Xcode 27 includes an app modernization skill that can automate many adaptivity migrations.

Resizable iPhone apps are now a core UIKit requirement

In iOS and macOS 27, iPhone apps can be fully resized in iPhone Mirroring on Mac. iPhone-only apps running on iPad are also fully resizable like other iPad apps. UIKit apps should dynamically adjust to the available scene size instead of assuming a fixed device screen or orientation.

The session frames modernization around four common legacy areas: adopting UIScene lifecycle, removing main-screen references, replacing user-interface-idiom layout decisions, and replacing interface-orientation layout decisions.

  • Build and test with the iOS 27 SDK to surface the new behavior.
  • Adopt UIScene lifecycle; apps that still use only the legacy app lifecycle will no longer launch when built with the latest SDKs.
  • Treat resizing as a runtime layout condition, not as a device-family or orientation switch.
  • Use size classes and view sizes for layout, with finer-grained decisions based on local view bounds when needed.

Replace main screen and screen-bounds assumptions

UIScreen.main always describes the device's main screen, which may not be the screen associated with a specific scene in iPhone Mirroring or on an external display. Code that needs screen information should use the local window scene, or better, avoid screen references where UIKit provides more adaptive alternatives.

For display scale, prefer traitCollection.displayScale. UIKit's automatic trait tracking can re-run common layout and drawing methods when tracked traits change. Where automatic tracking is not available, register for trait changes explicitly. For available space, prefer UIWindowScene effective geometry at the scene level and local view bounds inside views and view controllers.

  • Use window?.windowScene?.screen instead of UIScreen.main when a screen reference is unavoidable.
  • Use traitCollection.displayScale instead of screen.scale.
  • Use windowScene.effectiveGeometry for scene-level available space.
  • Use view.bounds or a containing view's bounds for local layout decisions.

Use local screen and trait references

Use the scene's screen only when needed, and replace screen scale reads with the trait collection display scale.

// Access the correct screen through a window scene
let screen = window?.windowScene?.screen

func generateThumbnail(_ image: UIImage, screen: UIScreen) -> UIImage {
    // Existing code, replacing main screen with local screen reference
}

override func layoutSubviews() {
    super.layoutSubviews()
    let displayScale = traitCollection.displayScale
    // Update layout/drawing that depends on scale
}

Track traits and effective geometry

Register for trait changes when automatic trait tracking is not enough, and use effective geometry or local bounds instead of screen bounds.

let displayScaleTrait: [UITrait] = [UITraitDisplayScale.self]
registerForTraitChanges(displayScaleTrait) { (view: GalleryView, previousTraitCollection: UITraitCollection) in
    view.cache.invalidate()
}

func windowScene(
    _ windowScene: UIWindowScene,
    didUpdateEffectiveGeometry previousEffectiveGeometry: UIWindowScene.Geometry
) {
    let geometry = windowScene.effectiveGeometry
    let availableSpace = geometry.coordinateSpace.bounds
    // React to scene geometry changes
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let availableSpace = view.bounds.size
    // Layout using the local view size
}

Modern layout signals: size classes, fullscreen games, and body protocols

The user interface idiom trait is no longer a reliable layout signal. An iPhone app running on iPad or in iPhone Mirroring may remain in the phone idiom while still being fully resizable. Interface orientation is also not useful for layout in resizable environments; supported orientations are treated as system preferences and may be ignored.

For games, UIRequiresFullscreen is honored on iPhone in resizable environments starting in iOS 27, but it no longer opts the app fully out of resizing. Instead, it enables discrete resizing that respects supported orientations so rendering can remain full quality in the available space.

UIView now conforms to the new Body protocols from CoreMotion and CoreLocation, allowing motion and heading data to be connected to the view that visualizes it so data stays in the correct coordinate space.

  • Replace userInterfaceIdiom layout checks with size-class checks or local size checks.
  • Replace interfaceOrientation layout checks with size classes or bounds-based layout.
  • Use UIRequiresFullscreen for games that need discrete resizing behavior.
  • Attach motion and heading bodies to the relevant UIView for orientation-independent coordinate handling.

Configure motion and heading bodies

Connect CoreMotion and CoreLocation managers to the UIView that visualizes the data.

override func viewDidLoad() {
    super.viewDidLoad()
    motionManager.deviceMotionBody = view
    locationManager.headingBody = view
}

New UIKit APIs for tabs, sidebars, navigation bars, and menus

iOS 27 lets iPhone apps opt into a sidebar representation for UITabBarController. Unlike iPad, this is an app choice, and the UI does not provide a user toggle between sidebar and tab bar. The system decides whether there is enough space to display the sidebar.

UITabBarController can also mark any tab as prominent so it remains visible when the tab bar collapses during scrolling. Navigation bars can now slide away interactively during scroll; apps can use the default system behavior or override it per navigation item.

Menu element images may not appear by default in some contexts such as menu bars on iPadOS and macOS. Use preferredImageVisibility only when an image must remain visible, and review the Human Interface Guidelines for menu imagery.

  • Set tabBarController.sidebar.preferredPlacement = .sidebar to opt into sidebar layout on iPhone.
  • Check tabBarController.sidebar.isAvailable before relying on sidebar presentation.
  • Set prominentTabIdentifier to keep an important tab visible during tab bar collapse.
  • Use navigationItem.barMinimizationBehavior and barMinimizationSafeAreaAdjustment to control navigation bar minimization.
  • Re-evaluate custom scroll edge effect styles, especially previous overrides from .automatic to .soft.

Opt into sidebar layout and check availability

An iPhone app can request sidebar placement, while the system determines whether the environment supports showing it.

tabBarController.sidebar.preferredPlacement = .sidebar

if tabBarController.sidebar.isAvailable {
    // Sidebar representation can be shown
} else {
    // Surface nested-tab UI elsewhere
}

Prominent tabs and navigation bar minimization

Pin an important tab and customize whether navigation bars minimize during scroll, including safe-area behavior when the app handles insets itself.

let tabs = [
    // ...
]
let tabBarController = UITabBarController(tabs: tabs)
tabBarController.prominentTabIdentifier = "cart"

navigationItem.barMinimizationBehavior = .always
navigationItem.barMinimizationSafeAreaAdjustment = .never

Apple Intelligence integration and Xcode agentic modernization

Menus in iOS 27 can show an Ask Siri button when there is content relevant for Siri. Apps can provide more specific context using the View Annotations API by annotating views with AppEntities. If an app supports drag and drop, Siri can load resources from the app's drag handlers when Apple Intelligence is invoked from context menus.

Drag delegate code should account for sessions that start without a user gesture. Avoid starting animations or presenting modal UI from sessionWillBegin; move user-gesture-dependent stateful UI to sessionDidMove.

Xcode 27 includes an app modernization skill that understands the adaptivity migrations covered here. It can convert main-screen usage to trait-collection or scene-bounds checks, add invalidation logic, replace orientation checks with size-class checks, and help migrate to scene lifecycle. Skills can be exported as Markdown for other workflows.

  • Use View Annotations and AppEntities to improve Siri context where appropriate.
  • Review drag-and-drop delegates for Apple Intelligence-triggered loading paths.
  • Use Device Hub and Xcode Previews resize mode to test arbitrary simulator sizes, then validate iPhone Mirroring and iPad on real devices.
  • Try Xcode's app modernization skill for large UIKit adaptivity audits.

Export Xcode skills for other tools

Exports Xcode skills as Markdown files that can be imported into other agentic coding workflows.

xcrun agent skills export

Resources

Unofficial, not associated with Apple. BySuperwall

On this page

Ask AI