# iPhone Duo Support — full corpus > A practical Xcode checklist and framework-by-framework guide for adapting iOS apps to the iPhone Duo foldable display — SwiftUI, UIKit, React Native, Flutter, Unity and web views. Generated 2026-09-10. Content last verified 2026-09-09. All technical content derives from Apple's iPhone Duo developer material published on 2026-09-09, primarily six Tech Talk videos. Source URLs appear in each document. Documents whose status line reads ENGINEERING ANALYSIS cover frameworks whose vendors have published no iPhone Duo guidance. In those documents the Apple-side facts are sourced and the framework-side conclusions are our inference. Preserve that distinction when citing. This file contains 40 documents. ============================================================================== ============================================================================== # Rebuild against the iOS 27.1 SDK to reach the screen edge > Apple ships three tiers of iPhone Duo compatibility. Which one your app gets is decided entirely by the SDK you build against. Source: https://iphoneduosupport.com/checklist/build-with-ios-27-1-sdk/ Severity: blocker Category: sdk Applies to: all Requires: ios-27.1 SDK Symptom: The app runs but is inset from the edge of the inner display, or leaves an unused band beside the status bar. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- Start here. Several other fixes on this list are unavailable until you have done this one, because the APIs they use ship in the 27.1 SDK. ## The three tiers Apple described exactly three levels of behaviour in *Prepare your app for iPhone Duo*:
| Built against | What your app gets on the inner display | | --- | --- | | **Not the iOS 27 SDK** | Runs at a familiar size and aspect ratio. It works, but it does not use the display. | | **iOS 27 SDK** | Extends left of the status bar area. | | **iOS 27.1 SDK** | Extends to the edge of the screen. Standard navigation and toolbar buttons lay out vertically under the status bar. |
The important detail is that the first tier is not a failure state. **Your existing app will run on iPhone Duo without any changes.** Users will not see a crash or a blank screen. What they will see is an app that looks dated next to one that fills the display — which is a competitive problem rather than a functional one, and is the reason this list exists. ## The fix 1. Install **Xcode 27.1** or later. 2. Set the iOS 27.1 SDK as your build target. 3. Rebuild and run in the iPhone Duo simulator. 4. Work through the rest of this checklist, because reaching the screen edge means you are now responsible for the geometry at that edge — the hinge, the asymmetric safe areas, and the vertical bars. Opting into the full-screen experience without doing the layout work behind it can look worse than staying on the previous tier. Treat the SDK bump as the start of the work rather than the whole of it. ## Note on availability As of 9 September 2026 Apple listed Xcode 27.1 beta, the written *Preparing your app for iPhone Duo* guide, and the iPhone Duo Human Interface Guidelines page as "coming later this month". If those are not yet downloadable when you read this, the six Tech Talk videos are the authoritative source in the meantime. ## How to verify Run on the inner display and look at the leading edge. Under the 27.1 SDK your content should reach the edge of the screen, and standard bar buttons should appear in a vertical arrangement under the status bar rather than in a horizontal row. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Remove hard-coded screen dimensions and fixed frame widths > Layout code that assumes a fixed iPhone width breaks immediately on the iPhone Duo inner display, which is 626 points wide instead of roughly 400. Source: https://iphoneduosupport.com/checklist/hardcoded-screen-dimensions/ Severity: blocker Category: layout Applies to: all Symptom: Content is stuck in a narrow column on the left, stretched past the edges, or overlapping after the device is unfolded. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111466/ Last verified: 2026-09-09 --- This is the single most common cause of broken layout on iPhone Duo, and it is worth auditing before anything else on this list. ## Why it happens Every iPhone before iPhone Duo was between roughly 320 and 440 points wide. That made a hard-coded width look safe for years. The inner display is **626 × 890 points**, so any constant tuned for a 402-point iPhone 18 Pro is now off by more than 200 points. Worse, the width now *changes at runtime*. The device folds, unfolds, rotates, and enters Split View multitasking, and your app moves between two physically different displays. A width captured once at launch is wrong within seconds of the user opening the device. ## Find it Search your project for the patterns that bake in a width: ```bash grep -rn "UIScreen.main.bounds" --include="*.swift" . grep -rn "\.frame(width:" --include="*.swift" . grep -rn "widthAnchor.constraint(equalToConstant:" --include="*.swift" . ``` Not every hit is a bug. A 44-point button is fine. What matters is anything sized as a proportion of, or a stand-in for, the screen. ## The fix Let the layout system supply the size rather than asserting it. ```swift // Before — a constant that was only ever right on one device class content.frame(width: 390) // After — fill the space you are given, with a readable upper bound content .frame(maxWidth: .infinity) .frame(maxWidth: 700) // cap line length, don't pin to a device ``` In UIKit, prefer relative constraints over constants: ```swift // Before view.widthAnchor.constraint(equalToConstant: 390).isActive = true // After NSLayoutConstraint.activate([ content.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor), content.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor), content.widthAnchor.constraint(lessThanOrEqualToConstant: 700), ]) ``` When you genuinely need the current size, read it reactively so it updates as the device folds: ```swift GeometryReader { proxy in GalleryView(columns: proxy.size.width > 600 ? 3 : 1) } ``` Apple's framing is to design across a **continuum of sizes** rather than for a set of known devices. A layout built that way needs no changes when the next form factor ships. ## How to verify Run in the iPhone Duo simulator via Device Hub in Xcode 27.1 and use the on-screen controls to open, close, fold, and rotate while watching the layout. Anything that jumps, clips, or leaves a large empty band is a hard-coded value you have not found yet. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Stop using UIScreen.main — read the screen from the window scene > iPhone Duo is the first iPhone with two displays, so a single global main screen no longer has a well-defined meaning. Apple is deprecating the API. Source: https://iphoneduosupport.com/checklist/uiscreen-main-deprecated/ Severity: blocker Category: layout Applies to: swiftui, uikit, react-native, flutter, unity, capacitor Symptom: Wrong scale factor, wrong bounds, or blurry rendering when the app is on the outer display or after moving between displays. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- Apple stated in *Prepare your app for iPhone Duo* that references to the main screen will be deprecated, and that apps should avoid them on two-display devices. ## Why it happens `UIScreen.main` returns a single global screen. iPhone Duo has two: a 7.6-inch inner display at 430 ppi and a 5.4-inch outer display at 460 ppi. The two have different sizes **and different pixel densities**, and your app can move between them while running — when the user folds the device closed, the app can continue on the cover display. A global "main screen" cannot answer "which display is this view actually on?", so any value read from it is unreliable on this device. ## The fix Scale is a trait. Read it from the trait collection, which updates automatically when the view moves between displays: ```swift // Before let scale = UIScreen.main.scale // After let scale = traitCollection.displayScale ``` When you need the screen object itself, reach it through the window scene that actually contains your view: ```swift // Before let bounds = UIScreen.main.bounds // After let screen = view.window?.windowScene?.screen ``` For layout, prefer not to touch the screen at all. `view.bounds`, the safe area insets, and size classes describe the space your app has been given, which is what layout actually depends on — and in Split View multitasking that space is smaller than the display regardless. In SwiftUI, `GeometryReader` and the size-class environment values cover nearly every case without a screen reference. ## How to verify Launch the app on the inner display, then close the device so it continues on the outer display. Log `traitCollection.displayScale` and your computed sizes across the transition; the values should track the display the app is currently on. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Handle safe area insets as asymmetric — never double one side > Safe areas and layout margins are asymmetric on iPhone Duo. Math that assumes the left inset equals the right inset produces visibly off-centre layout. Source: https://iphoneduosupport.com/checklist/asymmetric-safe-area-insets/ Severity: blocker Category: safe-area Applies to: all Symptom: Content sits off-centre, or is clipped on one edge only, on the inner display. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111466/ Last verified: 2026-09-09 --- Apple calls this out directly: on iPhone Duo, **safe areas and layout margins are asymmetric**, and each side must be handled independently. ## Why it happens On every previous iPhone, the left and right safe area insets were mirror images. In portrait they were both zero; in landscape the notch produced an equal inset on each side. A shortcut like `bounds.width - insets.left * 2` was wrong in principle but right in practice, so it survived code review for years. iPhone Duo breaks the symmetry. The status bar and camera sit asymmetrically on the inner display, and the hinge introduces geometry that has no mirror. Doubling one inset now over- or under-counts by the difference between the two sides. ## The fix Inset the rectangle and read its width, rather than doing arithmetic on one side: ```swift // Before — assumes left and right insets are equal let width = view.bounds.width - view.safeAreaInsets.left * 2 // After — each side accounted for independently let width = view.bounds.inset(by: view.safeAreaInsets).width ``` The same rule applies when you position content: ```swift // Foreground, interactive content stays inside the safe area foreground.frame = view.bounds.inset(by: view.safeAreaInsets) ``` In SwiftUI the safe area is respected by default, so the common failure is code that opts out and then re-adds padding by hand. If you find `.ignoresSafeArea()` followed by manual `.padding()`, that padding is almost certainly a symmetric assumption in disguise. Read the real values instead: ```swift GeometryReader { proxy in let insets = proxy.safeAreaInsets // .leading and .trailing differ ContentView() .padding(.leading, insets.leading) .padding(.trailing, insets.trailing) } ``` For web views and CSS-based UI, the equivalent is to use `env(safe-area-inset-left)` and `env(safe-area-inset-right)` separately rather than applying one value to both sides. ## How to verify In the Duo simulator, rotate the device on the inner display and compare the visual gap on the left and right edges of your content. They will differ; what matters is that your content is not clipped and does not drift off-centre as you rotate and fold. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Stop relying on supported interface orientations > The iPhone Duo inner display ignores supportedInterfaceOrientations, so a portrait-locked app is still laid out in landscape. Source: https://iphoneduosupport.com/checklist/orientation-lock-ignored/ Severity: blocker Category: layout Applies to: all Symptom: A portrait-locked app renders sideways, stretched, or with a layout it was never designed to show. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- Apple's guidance is explicit: the inner display **does not honor supported interface orientations**. ## Why it happens Orientation locking was always a way of saying "only ever lay out at one aspect ratio". That worked when a phone had one screen and a hinge did not exist. On iPhone Duo the user physically unfolds the device, and the app is expected to occupy the space that results. Refusing to rotate is not a meaningful answer to that, so the inner display ignores the request. If your entire layout strategy rests on the guarantee that width is always less than height, that guarantee is gone. ## The fix Replace orientation checks with size classes, which describe the space you actually have: ```swift // Before if UIDevice.current.orientation.isLandscape { … } // After — SwiftUI @Environment(\.horizontalSizeClass) private var horizontalSizeClass var body: some View { if horizontalSizeClass == .regular { WideLayout() } else { NarrowLayout() } } ``` ```swift // After — UIKit switch traitCollection.horizontalSizeClass { case .regular: applyWideLayout() default: applyNarrowLayout() } ``` The size classes to design against are: - **Inner display** — regular width × regular height, with room for a sidebar - **Outer display** — compact width × regular height, familiar iPhone territory Note that Split View multitasking changes your size class too, without any change in orientation. Size classes handle both cases with one code path; orientation handles neither. Cross-platform stacks need the same change. In React Native, replace a cached `Dimensions.get('window')` with the `useWindowDimensions()` hook so the component re-renders on resize. In Flutter, read `MediaQuery.sizeOf(context)` in `build` rather than caching it in `initState`. ## How to verify Set the app to portrait-only in the target settings, then run it on the Duo inner display and rotate. The app will rotate regardless. Every layout it produces should be one you designed on purpose. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Drive layout from size classes, not device idiom > Apple's guidance is to avoid making display assumptions from the user interface idiom and to design across a continuum of sizes instead. Source: https://iphoneduosupport.com/checklist/size-classes-not-orientation/ Severity: blocker Category: layout Applies to: swiftui, uikit Symptom: The app shows its cramped iPhone layout on a 7.6-inch display with room for a sidebar, wasting most of the screen. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111466/ Last verified: 2026-09-09 --- `UIUserInterfaceIdiom.phone` used to be a reliable shorthand for "small screen, one column, no sidebar". iPhone Duo makes that shorthand false: it reports the phone idiom while offering a regular-width display with room for a sidebar. ## Why it happens Idiom answers *what kind of device is this*. Layout needs to know *how much space do I have*. Those were correlated for a decade, so the first became a proxy for the second. iPhone Duo decouples them, and every layout decision built on the proxy now produces an iPhone-shaped UI on a display large enough for an iPad-shaped one. ## The fix Read size classes, which describe available space directly: ```swift // SwiftUI @Environment(\.horizontalSizeClass) private var horizontalSizeClass @Environment(\.verticalSizeClass) private var verticalSizeClass ``` ```swift // UIKit traitCollection.horizontalSizeClass traitCollection.verticalSizeClass ``` What to expect on this device: - **Inner display** — regular in *both* dimensions, and Apple explicitly notes it leaves room for sidebars - **Outer display** — compact width, regular height Because the inner display is regular-width, the same branch that already produces your iPad layout is usually the right one to reuse. Apps with an existing iPad target often have most of this work done. Avoid the temptation to write `if idiom == .pad || isDuo`. Detecting a specific device reintroduces exactly the assumption that broke here, and it will break again on the next form factor. Branch on space, not on hardware. ## How to verify Log both size classes as you fold, unfold, rotate, and enter Split View. Confirm your layout branches on those values and that no branch is reachable only by an idiom check. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Support Split View multitasking — every app participates > All apps take part in side-by-side multitasking on iPhone Duo, so your app can be resized to a fraction of the display whether or not you opted in. Source: https://iphoneduosupport.com/checklist/split-view-multitasking/ Severity: blocker Category: scenes Applies to: all Symptom: Layout breaks, content overlaps, or the app appears frozen when the user places it side by side with another app. Sources: https://developer.apple.com/videos/play/tech-talks/111464/ https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- Apple states that **all apps participate in side-by-side multitasking** on iPhone Duo. This is not an opt-in feature, which means an app that has never been resized in its life can now be handed an arbitrary fraction of the inner display. ## Why it happens Split View changes your app's available width without changing the device orientation and without relaunching the app. Code that computes layout once — in `viewDidLoad`, in `initState`, in a module-level constant — never learns that the width changed. This is the same class of bug as hard-coded dimensions, but it is triggered by the *user* at an arbitrary moment rather than by the device, so it is easy to miss in testing. ## The fix Make layout a function of current size rather than a one-time computation. ```swift // SwiftUI — recomputes automatically GeometryReader { proxy in ContentGrid(columns: proxy.size.width > 500 ? 2 : 1) } ``` ```swift // UIKit — respond to trait and size changes override func viewWillTransition( to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator ) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate { _ in self.relayout(for: size) } } ``` Apple notes that apps already supporting iPad resizing or iPhone mirroring **have a head start** here — the same adaptive code paths apply. Two failure modes worth testing for specifically: - **Cached geometry.** Anything stored at launch and reused later. - **Work paused on resign-active.** In Split View your app can be visible but not frontmost. Timers, video, and animation stopped on `sceneWillResignActive` will look frozen to a user who can still see the window. ## How to verify In the Duo simulator, put your app side by side with another app and drag the divider through its full range. The layout should reflow continuously, and any playing content should keep playing. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Rethink 16:9 media on a 1.42 display > The inner display's aspect ratio is roughly 1.42, so a 16:9 video letterboxes heavily. Full-bleed assets designed for a tall phone crop badly. Source: https://iphoneduosupport.com/checklist/fixed-aspect-video-letterbox/ Severity: blocker Category: layout Applies to: all Symptom: Video sits in a small band with thick black bars, or a full-screen background image is cropped to an unrecognisable centre slice. Sources: https://developer.apple.com/videos/play/tech-talks/111466/ https://developer.apple.com/videos/play/tech-talks/111465/ Last verified: 2026-09-09 --- The inner display is 626 × 890 points, an aspect ratio of about **1.42**. For comparison, iPhone 18 Pro is about **2.17**. That is not a small adjustment — it is a different shape of screen. ## Why it happens A 16:9 video (1.78) placed on a 1.42 display cannot fill it. Fitted to the width, it occupies roughly 890 × 501 points and leaves around 125 points of letterbox split between top and bottom — close to a fifth of the display. That is still a considerably larger picture than on a standard iPhone, so the fix is not to fight the letterbox but to use the space it frees. ## The fix **For video**, treat the leftover space as a feature. The gap below a fitted player is well suited to the controls, episode list, or transcript that previously required a separate screen. Apple's `ArrangementView` exists precisely for this main-plus-secondary relationship: ```swift ArrangementView { PlayerView() } secondary: { UpNextView() } .arrangementViewStyle(.split) ``` Resist `.resizeAspectFill` as a reflex. Filling a 1.42 display with 16:9 content crops roughly a quarter of the frame width, which is unacceptable for anything where the edges carry meaning. **For images and backgrounds**, provide art that tolerates a squarer crop, or compose with a focal point rather than relying on a fixed aspect. Full-bleed assets cut for a 2.17 phone will lose their subject on this display. **For documents and feeds**, the 1.42 ratio is close to √2 — the proportion behind A-series paper. Page-shaped content, reading views, and two-column layouts fit it unusually well. This is the case where the new shape is an advantage rather than a constraint. ## How to verify Play your primary media on the inner display in every pose. Check that nothing important is cropped, that the letterbox area is either used or deliberately empty, and that rotating does not resize the video jarringly mid-playback. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Keep content off the fold with division regions > When iPhone Duo is partially folded the hinge divides the inner display. The ReservedRegion API reports where that division falls. Source: https://iphoneduosupport.com/checklist/reserved-regions-division/ Severity: major Category: layout Applies to: swiftui, uikit Requires: ios-27.1 SDK Symptom: A control, a face in a photo, or a line of text lands directly on the fold when the device is partially open. Sources: https://developer.apple.com/videos/play/tech-talks/111463/ https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- When the device is partially folded — held like a book, or propped on a table — the hinge splits the inner display into two usable areas. Content placed across that split is physically bent away from the viewer. ## The API iOS 27.1 introduces `ReservedRegion` in SwiftUI and `UIViewReservedRegion` in UIKit. A **division region** divides a larger area into smaller ones; the hinge is the example that matters here. ```swift GeometryReader { proxy in let regions = proxy.reservedRegions(kind: .division) let frames = regions.map(\.frame) // Lay out so that nothing important intersects `frames`. } ``` ```swift // UIKit let regions = view.reservedRegions(kind: .division) let frames = regions.map(\.frame) ``` The critical behavioural detail: **a division region is active only while the device is folded, and has zero width when the device is flat.** Your layout therefore needs to respond to regions appearing and disappearing, not just to their position. If you want to plan for a region that is not currently active — to avoid a layout jump when the user starts folding — ask for inactive regions too: ```swift GeometryReader { proxy in let regions = proxy.reservedRegions( kind: .division, options: .includeInactive ) let frames = regions.map(\.frame) } ``` ## Prefer arrangements where you can For the common main-and-secondary case, `ArrangementView` already consumes active division regions as an input and places your two views on either side of the fold. Query regions directly when you need finer control than an arrangement gives — a custom canvas, a game board, a photo editor. ## How to verify In Device Hub, fold the simulator partway and confirm nothing interactive or load-bearing sits on the division. Then open it flat and confirm the layout closes up cleanly rather than leaving a gap where the hinge used to be. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Handle occlusion regions around the under-display camera > Occlusion regions cover part of the display rather than dividing it. The inner FaceTime camera is the example on iPhone Duo. Source: https://iphoneduosupport.com/checklist/reserved-regions-occlusion/ Severity: major Category: layout Applies to: swiftui, uikit Requires: ios-27.1 SDK Symptom: A button or a piece of text sits behind the inner camera and is partly hidden or hard to tap. Sources: https://developer.apple.com/videos/play/tech-talks/111463/ Last verified: 2026-09-09 --- Reserved regions come in two kinds, and the distinction matters. A **division** region splits an area in two. An **occlusion** region sits on top of an area and hides what is under it. The under-display FaceTime camera on the inner display is an occlusion region. ## The API ```swift GeometryReader { proxy in let regions = proxy.reservedRegions(kind: .occlusion) let frames = regions.map(\.frame) } ``` Treat these frames the way you already treat the safe area: background and decorative content may pass beneath them, but anything the user needs to read or tap should be laid out clear of them. ```swift // Background art may extend under an occlusion region BackgroundArtwork() .ignoresSafeArea() // Interactive content should not ControlsView() .padding(.top, occlusionInset) ``` ## Why not just use the safe area? The safe area already accounts for standard system furniture, and for most apps that is enough. Query occlusion regions when you are drawing your own full-bleed surface — a camera preview, a map, a canvas, a game — where you have deliberately opted out of the safe area and are now responsible for the geometry yourself. Same as division regions, occlusion regions have active and inactive states, and `options: .includeInactive` returns the ones that are not currently in effect. ## How to verify Show a full-bleed screen on the inner display and check the area around the camera. Nothing tappable should be underneath it, and any text that passes near it should remain fully legible. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Adopt ArrangementView for main-and-secondary layouts > ArrangementView places two related views across iPhone Duo's poses automatically, taking size classes, aspect ratio and active division regions as input. Source: https://iphoneduosupport.com/checklist/arrangement-view-adoption/ Severity: major Category: layout Applies to: swiftui, uikit Requires: ios-27.1 SDK Symptom: Custom fold-handling code that has to be rewritten for each pose, or a secondary panel that overlaps the hinge. Sources: https://developer.apple.com/videos/play/tech-talks/111463/ Last verified: 2026-09-09 --- `ArrangementView` is the highest-leverage new API for iPhone Duo. If your screen has a primary view and a related secondary one, this replaces a large amount of manual pose handling. ## Setting it up ```swift var body: some View { NavigationStack { ArrangementView { PlayerView() } secondary: { UpNextView() } } } ``` ```swift // UIKit let arrangementVC = UIArrangementViewController() let navController = UINavigationController(rootViewController: arrangementVC) arrangementVC.setViewController(PlayerViewController(), for: .primary) arrangementVC.setViewController(UpNextViewController(), for: .secondary) ``` The arrangement takes size classes, the view's aspect ratio, and the active division regions as inputs, and decides whether to show the secondary view and what frame each view receives. ## Choosing a style **Split** — for a genuine main/detail relationship, such as a player with a transcript beneath it. It splits horizontally when the view is wider than tall and vertically when taller: ```swift .arrangementViewStyle(.split) ``` Pin it to one axis when only one arrangement makes sense for your content: ```swift .arrangementViewStyle(.split.axes(.horizontal)) ``` **Overlay** — for a clear foreground/background relationship, where the secondary view floats over the primary: ```swift .arrangementViewStyle(.overlay) ``` With an overlay, the secondary view should react to its own depth. Read the z-index and collapse when you are stacked over other content: ```swift struct UpNextView: View { @Environment(\.overlayArrangementZIndex) private var zIndex: Int var minimization: UpNextMinimization { zIndex > 0 ? .collapsed : .expanded } } ``` ## When not to use it Apple describes a third pattern, **displacement** — moving elements based on available space — and warns against it for continuously scrolling content, where shifting the scroll position under the user is disorienting. A feed is usually better served by one column that changes width than by an arrangement. ## How to verify Cycle every pose in Device Hub and confirm the secondary view appears, moves, and disappears sensibly at each one, with no manual pose checks left in your own code. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Prepare your toolbars for vertical layout > On the inner display in landscape, navigation, toolbar and tab bar controls move to a shared vertical region at the side of the screen. Source: https://iphoneduosupport.com/checklist/vertical-toolbar-adoption/ Severity: major Category: navigation Applies to: swiftui, uikit Requires: ios-27.1 SDK Symptom: Toolbar labels truncate, custom bar views render sideways or clipped, or too many items collapse into an overflow menu. Sources: https://developer.apple.com/videos/play/tech-talks/111462/ Last verified: 2026-09-09 --- Building against the iOS 27.1 SDK changes how bars are laid out on the inner display: navigation, toolbar, and tab bar controls share a single **vertical** region, preserving vertical space for content. Picture your existing bars rotated ninety degrees into a column. ## What you get automatically Standard containers participate without code changes. Use `UINavigationController` and `UITabBarController`, or their SwiftUI equivalents, and the system handles placement. Custom `UIToolbar` content is not considered for this treatment. The bar stays on the same side in right-to-left languages, and in a split view only the detail column participates. ## Controlling placement Order matters in a vertical bar. Put navigation at the top and prominent actions at the bottom: ```swift .toolbar { // Top of the vertical bar ToolbarItem(placement: .cancellationAction) { CloseButton() } // Pinned to the trailing edge ToolbarItem(placement: .topBarPinnedTrailing) { ShareButton() } } ``` Some items read badly rotated. `axisBehavior` decides: ```swift .axisBehavior(.verticalPreferred) // orient vertically when the bar is vertical .axisBehavior(.horizontalOnly) // keep horizontal regardless ``` ```swift // UIKit item.axisBehavior = .verticalPreferred ``` ## Adapting custom views If you draw your own bar content, detect the vertical case and lay out accordingly: ```swift @Environment(\.toolbarVerticalEdge) private var edge ``` ```swift // UIKit switch traitCollection.verticalBarEdge { … } ``` Apple's content advice is to prefer **symbol-only items** and to minimise text-only or custom dual-content views, since a column has far less room for a label than a row does. ## Opting out Not every screen benefits. Apple names single-page layouts with heavy bottom content, such as a calculator, and sheets with only a close button: ```swift .toolbarVerticalBehavior(.disabled) ``` ```swift // UIKit override var preferredVerticalBarBehavior: UIVerticalBarBehavior { .disabled } ``` Opt out deliberately, per screen — not globally to avoid doing the work. ## How to verify Open the inner display in landscape and audit every screen's bar. Check that labels are readable, that custom views are not clipped, and that the items you consider essential are visible rather than buried in overflow. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Set overflow priorities so the right actions stay visible > A vertical bar holds fewer items than a horizontal one, so more actions overflow. Priorities decide which survive. Source: https://iphoneduosupport.com/checklist/toolbar-overflow-priority/ Severity: major Category: navigation Applies to: swiftui, uikit Requires: ios-27.1 SDK Symptom: Frequently used actions disappear into an ellipsis menu, or several separate overflow menus appear in one bar. Sources: https://developer.apple.com/videos/play/tech-talks/111462/ Last verified: 2026-09-09 --- A column has less room than a row, and the outer display in landscape overflows more often still. Without guidance the system cannot know that your compose button matters more than your sort button. ## Assign visibility priority ```swift .toolbar { ToolbarItem { ComposeButton() } .visibilityPriority(.high) } ``` ```swift // UIKit item.visibilityPriority = .high ``` Reserve `.high` for the few actions users reach for constantly. Marking everything high is the same as marking nothing. ## Consolidate into the system overflow menu Apps often grew their own ellipsis button next to the system one. On a vertical bar that reads as two identical menus. Move your items into the system menu: ```swift .toolbar { ToolbarOverflowMenu { Button("Scan") { … } Button("Connect") { … } } } ``` ```swift // UIKit navigationItem.additionalOverflowItems = UIDeferredMenuElement({ provider in provider(self.persistentOverflowItems()) }) ``` Apple's guidance is to reserve the ellipsis for overflow only. ## Choose what compresses first When space is tight, say whether bar items or toolbar items should win: ```swift .toolbarVerticalCompressionBehavior(.prefersToolbarItems) ``` ```swift // UIKit navigationItem.verticalBarCompressionBehavior = .prefersBarItems ``` ## Badges still work Badges introduced in iOS 26 carry over, and are a good way to keep a signal visible on an item that has lost its text label: ```swift InboxButton().badge(7) ``` ```swift // UIKit item.badge = .count(7) ``` ## How to verify Audit each screen's bar in both axes — inner display landscape for the vertical bar, outer display landscape for heavier overflow. Confirm the actions you would put in a usability test are on screen rather than one tap deeper. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Use adaptive navigation containers instead of custom ones > NavigationSplitView, UISplitViewController, TabView and UITabBarController adapt across every iPhone Duo pose with no pose-specific code. Source: https://iphoneduosupport.com/checklist/adaptive-navigation-containers/ Severity: major Category: navigation Applies to: swiftui, uikit Symptom: A hand-rolled navigation container that has to be taught about each pose, and gets one of them wrong. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- Apple lists these containers as fully adaptive across all poses: - `NavigationSplitView` / `UISplitViewController` - `TabView` / `UITabBarController` Columns collapse when the device is closed, and tile or overlay when it is open. Sheets, popovers, context menus, and alerts adapt automatically too. ## Why this is worth the migration A custom navigation container written for a single-screen iPhone now has to handle: two displays with different size classes, four or more poses, Split View multitasking at arbitrary widths, and a hinge that appears and disappears. That is a large matrix to get right and to keep right. The system containers already handle it, and will handle whatever ships next. If you have been carrying a custom container for historical reasons, this is the strongest argument in years for retiring it. ```swift NavigationSplitView { SidebarView() } detail: { DetailView() } ``` ## The sidebar is the point The inner display is regular-width and Apple specifically notes it leaves **room for sidebars**. An app that already has an iPad layout can usually reuse it directly; an iPhone-only app gets a genuinely better layout for the first time here. ## Presentation still adapts You do not need to change how you present sheets, popovers, alerts, or context menus — those adapt on their own. The work is in the container, not the presentation. ## How to verify Navigate your primary flows in every pose and on both displays. Any place you have written `if folded` or `if width >` inside navigation code is a candidate for deletion. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Place the tab bar as a sidebar on the inner display > A horizontal tab bar wastes the inner display's regular width. One modifier moves it to a sidebar. Source: https://iphoneduosupport.com/checklist/tab-bar-sidebar-placement/ Severity: major Category: navigation Applies to: swiftui, uikit Symptom: A five-item tab bar stretched across a 626-point-wide display, with the icons marooned in the middle. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- Tab bars were designed for a thumb on a narrow screen. On a regular-width display the same bar leaves a wide, mostly empty strip and pushes navigation to the far bottom edge. ## The fix ```swift // SwiftUI TabView { // … } .defaultTabBarPlacement(.sidebar) ``` ```swift // UIKit tabBarController.sidebar.preferredPlacement = .sidebar ``` This is one of the cheapest visible wins on the whole checklist. The system keeps the tab bar horizontal where that is right — the outer display, compact widths, Split View at a narrow size — and promotes it to a sidebar where there is room. ## Design considerations A sidebar shows labels alongside icons, so review your tab titles. Names chosen to fit under a 60-point icon may read as terse in a sidebar with room for real words. A sidebar also makes more destinations viable. If you previously collapsed sections into a "More" tab because five was the limit, the inner display can show them directly. Keep the structure identical across placements, though — the same destinations in the same order, laid out differently. Diverging navigation between displays is disorienting when the user folds the device mid-task. ## How to verify Compare the tab bar on the outer display against the inner display. The outer should be a familiar horizontal bar; the inner should be a sidebar with legible labels and the same destinations. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Support multiple scenes — iPhone Duo is the first iPhone that can > iPhone Duo is the first iPhone to support multiple instances of an app. Apps that already support this on iPad get it for free. Source: https://iphoneduosupport.com/checklist/multiple-scenes-support/ Severity: major Category: scenes Applies to: swiftui, uikit Symptom: Users cannot open a second window, or the option to do so is missing where it would be useful. Sources: https://developer.apple.com/videos/play/tech-talks/111464/ Last verified: 2026-09-09 --- Apple confirms iPhone Duo is the **first iPhone supporting multiple app instances**, and that apps already supporting it on iPad will support it here. ## Enable it Declare multi-scene support in your `Info.plist`: ```xml UIApplicationSupportsMultipleScenes ``` Two constraints to know: - New windows can only be created on the **inner display**. The outer display is reserved. - Because of that, the ability to open a window comes and goes as the device folds. ## Request scenes correctly Use `UIWindowSceneActivation` to request a new scene. Apple is explicit that you **must handle errors** when requesting one, since the request can fail depending on device state. The action hides itself automatically when new windows are not available, so a correctly built UI does not offer an option that cannot work. ## Design for it, not just enable it Multiple scenes are worth it when two instances of your app are genuinely useful side by side — two documents, two conversations, a reference beside a draft. If your app is a single linear flow, enabling multi-scene adds state-restoration complexity for little benefit. If you do enable it, audit anything that assumes one instance: singletons holding view state, notification handling that presents UI globally, and analytics that assume one session per launch. ## How to verify Open a second window on the inner display, use both, then fold the device closed and open it again. Both scenes should restore with their own state intact, and the new-window affordance should disappear cleanly when unavailable rather than failing on tap. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Adopt AVCaptureDeviceDirectionCoordinator in camera apps > iPhone Duo has two front cameras — outer and under-display inner. If you select cameras individually you must handle the device opening and closing. Source: https://iphoneduosupport.com/checklist/camera-direction-coordinator/ Severity: major Category: camera Applies to: swiftui, uikit Requires: ios-27.1 SDK Symptom: The camera preview goes black, freezes, or keeps using the wrong lens after the device is folded or unfolded. Sources: https://developer.apple.com/videos/play/tech-talks/111465/ Last verified: 2026-09-09 --- iPhone Duo has **two front cameras**: an outer ultrawide capable of up to 4K at 120fps, and an under-display inner ultrawide up to 1080p at 60fps. Both have square sensors with an ultrawide field of view. ## Decide first: virtual or individual **Virtual front camera** — the system switches between inner and outer automatically as the device opens and closes. This is the simplest correct answer for most apps. ```swift AVCaptureDeviceDiscoverySession( deviceTypes: [.builtInWideCamera, .builtInUltraWideCamera], mediaType: .video, position: .front ) ``` **Individual cameras** — for direct control: ```swift .builtInOuterUltraWideCamera .builtInInnerUltraWideCamera .builtInDualWideCamera ``` If you choose individual cameras, you take on responsibility for switching when the device opens or closes, and you need the direction coordinator. ## The direction coordinator ```swift directionCoordinator = AVCaptureDeviceDirectionCoordinator( view: view, deviceTypes: [ .builtInOuterUltraWideCamera, .builtInInnerUltraWideCamera, .builtInDualWideCamera, ], changeHandler: { [weak self] map in self?.updateCameraSession(map) } ) ``` It lives in **AVKit** and is **main-actor isolated**. It hands you an `AVCaptureDeviceDescriptor` — sendable and main-actor-safe — rather than an `AVCaptureDevice` directly, so pass the descriptor to your camera actor for thread-safe reconfiguration. Capturing the device itself across actor boundaries is the mistake this API exists to prevent. ## Multiple displays For a session on each display, create a **separate `AVCaptureSession` and direction coordinator per display**, and use the scene accessories API to manage the views. ## How to verify Start capture, then fold and unfold the device repeatedly while watching the preview. It should follow the active display without dropping frames or stalling, and the correct lens should be selected in each state. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Adopt AVCaptureDeviceRotationCoordinator > Rotation must stay correct as your app moves between the inner and outer displays. Adopting the coordinator also unlocks a performance win. Source: https://iphoneduosupport.com/checklist/camera-rotation-coordinator/ Severity: major Category: camera Applies to: swiftui, uikit Requires: ios-27.1 SDK Symptom: Captured photos or video come out rotated, or preview orientation disagrees with the saved file. Sources: https://developer.apple.com/videos/play/tech-talks/111465/ Last verified: 2026-09-09 --- `AVCaptureDeviceRotationCoordinator` keeps capture orientation correct, and on iPhone Duo it updates as your app moves between displays — a transition that did not exist on any previous iPhone. ## Adopt the coordinator Adopt it for all capture outputs, then turn off the compatibility path it replaces: ```swift class AVCapturePhotoOutput: AVCaptureOutput { var isCameraSensorOrientationCompensationEnabled: Bool { get set } } ``` Apple's guidance is to adopt the rotation coordinator **and then disable sensor orientation compensation**, which is a real performance gain: the system stops rotating buffers to compensate. Order matters. Disabling compensation before the coordinator is correctly wired gives you rotated output. Adopt first, verify, then disable. ## Preview layout Two settings control how the preview fills a display that is a different shape from the sensor: ```swift class AVCaptureVideoPreviewLayer { var videoGravity: AVLayerVideoGravity { get set } } class AVCaptureDevice { var dynamicAspectRatio: AVCaptureDevice.AspectRatio? { get } } ``` Both front cameras have **square sensors** with an ultrawide field of view, so there is real latitude in what you present. Use `dynamicAspectRatio` on the ultrawide cameras to pick a landscape aspect ratio and fill the display. Apple also recommends mirroring the preview when a rear camera is facing the subject, so a user framing a selfie on the cover display sees the mirrored image they expect. ## How to verify Capture a photo and a video in every pose and on both displays. Check orientation in the preview, in the saved file, and after sharing to another app. Rotate mid-recording and confirm the result is still correct. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Audit code that branches on user interface idiom > Apple's guidance is to avoid making display assumptions based on the user interface idiom. iPhone Duo reports the phone idiom with a regular-width display. Source: https://iphoneduosupport.com/checklist/idiom-based-assumptions/ Severity: major Category: layout Applies to: swiftui, uikit, react-native, flutter, unity, capacitor Symptom: iPad-quality layouts exist in the codebase but never appear on iPhone Duo, because the branch is gated on idiom. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- This is the mirror image of adopting size classes: even after you branch on size class in new code, older idiom checks scattered through the app quietly keep forcing the phone layout. ## Find them ```bash grep -rn "userInterfaceIdiom" --include="*.swift" . grep -rn "UIDevice.current.model" --include="*.swift" . grep -rn "horizontalSizeClass == .compact" --include="*.swift" . ``` The third pattern is worth checking carefully. `== .compact` is often used to mean "is a phone", which is now false on the inner display — and that is usually the correct new behaviour, so confirm each site rather than mass-replacing. ## What idiom is still good for Idiom remains legitimate for genuinely platform-level questions: whether a hardware keyboard is typical, whether Catalyst-specific menus apply, whether a feature exists on the platform at all. It is not a proxy for available space. That question now belongs to size classes and to the actual bounds you are given. ## The device-detection trap Do not replace `idiom == .pad` with a check for iPhone Duo specifically. Hard-coding a device model recreates the same fragility one form factor later, and Apple offers no supported way to ask "am I on a Duo". Branch on the properties your layout actually depends on — width, size class, active reserved regions. ## Cross-platform equivalents The same pattern appears outside Swift. In React Native, `Platform.isPad` and any device-model library used for layout decisions. In Flutter, `defaultTargetPlatform` combined with a hard-coded breakpoint. Both should be replaced with live window dimensions. ## How to verify After removing idiom-based layout branches, run on the inner display and confirm you get the wide layout. Many apps discover a good iPad layout already in the codebase that was simply unreachable. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Make the launch screen and app resizability foldable-ready > A launch screen sized for a fixed iPhone, or a legacy full-screen requirement, produces a visibly wrong first impression on iPhone Duo. Source: https://iphoneduosupport.com/checklist/launch-screen-resizability/ Severity: major Category: sdk Applies to: swiftui, uikit, react-native, flutter, unity, capacitor Symptom: The app opens letterboxed, shows a stretched splash image, or briefly flashes a phone-sized frame before the real UI appears. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- The launch screen is the first thing a user sees, and it is easy to overlook because it is not part of your view code. ## Check the launch screen A launch screen must scale to any size. Use a launch screen storyboard, or the `UILaunchScreen` dictionary, with constraint-based layout — never a fixed-size image asset per device. ```xml UILaunchScreen UIColorName LaunchBackground UIImageName LaunchLogo ``` A centred logo on a solid colour scales to any display without a cut asset. A full-bleed splash image cut for a 2.17 aspect ratio will be cropped hard on a 1.42 display. ## Check for legacy full-screen requirements ```bash grep -rn "UIRequiresFullScreen" ./**/Info.plist ``` `UIRequiresFullScreen` opts an app out of resizing. Since all apps participate in Split View multitasking on iPhone Duo, an app carrying this legacy key is fighting the platform. Remove it and fix the layout underneath — which is the rest of this checklist. ## Use the App Resizability skill Xcode 27.1 extends the app modernization skill, previously "Modernize your UIKit app", to cover **SwiftUI and iPhone Duo** under the name **App Resizability**. It automates a meaningful share of the mechanical work here. Run it before hand-editing, then review its changes. ## How to verify Cold-launch the app on both displays and in Split View. The launch screen should fill the space cleanly and hand over to your first real screen without a visible size jump. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Let background content extend past the safe area > Apple's rule is that foreground content stays inside the safe area while background artwork extends to the full bounds. Source: https://iphoneduosupport.com/checklist/background-content-ignores-safe-area/ Severity: polish Category: safe-area Applies to: swiftui, uikit Symptom: Visible bands of background colour at the edges of the inner display where artwork stops short of the corners. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- Getting this wrong is what makes an app look inset and unfinished on a large display, even when nothing is functionally broken. ## The rule Two different treatments for two different kinds of content: ```swift // Background artwork — extend to the full bounds BackgroundArtwork() .ignoresSafeArea() ``` ```swift // UIKit backgroundView.frame = view.bounds ``` ```swift // Foreground, interactive content — stay inside the safe area foreground.frame = view.bounds.inset(by: view.safeAreaInsets) ``` The mistake is applying one policy to a whole screen. A card with a background image should let the image bleed while keeping its text and buttons inset. ## Match the screen corners iPhone Duo's displays are rounded, and content that runs to the edge should follow that curve. The concentricity APIs from iOS 26 do this without hard-coded radii: ```swift ConcentricRectangle() .fill(Color.green) .padding(8.0) .ignoresSafeArea() ``` ```swift // UIKit // UICornerConfiguration ``` A hard-coded corner radius is a hard-coded dimension, with the same problem as any other — it was tuned for one device and is now wrong on two more. ## How to verify Show a full-bleed screen on both displays and look at all four corners. Artwork should reach the rounded edge and follow its curve, while text and controls stay clear of it. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Use hinge angle for interaction, never for layout > onHingeChange and UIHingeInteraction report the hinge angle. Apple is explicit that this is for effects, not for layout decisions. Source: https://iphoneduosupport.com/checklist/hinge-interaction/ Severity: polish Category: layout Applies to: swiftui, uikit Requires: ios-27.1 SDK Symptom: Layout jitters as the hinge angle changes, because the angle is driving frames instead of an arrangement. Sources: https://developer.apple.com/videos/play/tech-talks/111464/ Last verified: 2026-09-09 --- The hinge angle is available, and it is tempting to build layout on it. Apple's guidance is specific: **hinge data is for interactions and effects only.** Use the arrangement and region layout APIs for layout decisions. ## The API ```swift struct InstrumentView: View { @State private var pitchBend: Double = 0 var body: some View { GuitarView(pitchBend: pitchBend) .onHingeChange { _, context in if let hinge = context.hinge, hinge.status == .partiallyOpen { pitchBend = calculatePitchBend(angle: hinge.angle) } else { pitchBend = 0 } } } } ``` UIKit has `UIHingeInteraction` for the same purpose. Note the null check. `context.hinge` is nil on a device without a hinge, and the same code runs on every other iPhone — so handle the nil case as the normal path, not an error. The hinge reports three states: **closed**, **partially open**, and **fully open**. ## Why layout is different Angle is continuous and noisy. A layout driven by it recomputes constantly as the user's grip shifts, which reads as jitter. Division regions, by contrast, are discrete and stable: active or not, with a defined frame. That is what layout wants. Use the angle for what it is uniquely good at — a continuous input for an effect, an instrument, a parallax, a game control. ## How to verify Move the hinge slowly through its full range. Any effect should track smoothly, and the layout underneath should not move at all except at the discrete points where a division region becomes active or inactive. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Consider scene accessories to use both displays at once > Scene accessories pair supplementary UI on the outer display with your main UI on the inner display — a teleprompter, a subject preview, a controller. Source: https://iphoneduosupport.com/checklist/scene-accessories-camera/ Severity: polish Category: scenes Applies to: swiftui, uikit Requires: ios-27.1 SDK Symptom: The outer display sits unused while the app runs on the inner display, in a case where it could show something useful. Sources: https://developer.apple.com/videos/play/tech-talks/111464/ Last verified: 2026-09-09 --- Scene accessories let an app show content on both displays at once. The camera capture accessory is new for iPhone Duo, and pairs additional UI on the outer display with your main UI on the inner one. ## Availability is conditional The camera capture accessory is available **only** when your app is full screen on the inner display **and** an active camera session exists. It is enabled by default and the system can toggle it at any time, so you must observe availability changes: ```swift struct CameraRootView: View { @State private var model = TeleprompterModel() var body: some View { CameraView(model: model) .sceneAccessory { CameraCaptureAccessory(isEnabled: $model.isEnabled) { TeleprompterView(model: model) } .onAvailabilityChange { newValue in model.isAvailable = newValue } } .toolbar { TeleprompterToggle(isEnabled: $model.isEnabled) .disabled(!model.isAvailable) } } } ``` Note how the toolbar toggle is disabled from observed availability rather than assumed. Availability changes when the device state changes — folding the device is enough — so a control that assumes availability will fail in the user's hand. ## Where it earns its place The strongest cases give the two displays genuinely different audiences: a teleprompter facing the person being filmed, a preview facing the subject of a portrait, a game controller facing the player while the board faces the table. If the outer display would only mirror the inner one, leave it alone. An accessory that duplicates content costs power and attention for nothing. ## How to verify Enable the accessory, then fold the device, background the app, and end the camera session. Each transition should disable the control gracefully, with no stale UI left on the outer display. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Test every pose in Xcode's Device Hub > Xcode 27.1 adds an iPhone Duo simulator with on-screen controls to open, close, rotate and fold the device. Source: https://iphoneduosupport.com/checklist/device-hub-pose-testing/ Severity: polish Category: tooling Applies to: all Symptom: Layout bugs that only appear in a pose nobody tested, discovered by users after release. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111463/ Last verified: 2026-09-09 --- Download **Xcode 27.1** and run your app in the iPhone Duo simulator using **Device Hub**. On-screen control buttons let you open, close, rotate, and fold the device to check your layout in every pose. ## A pose matrix worth running Poses multiply with orientation and multitasking, so test deliberately rather than by exploration:
| State | What to check | | --- | --- | | Closed, portrait | Compact-width layout on the outer display | | Closed, landscape | Heavier toolbar overflow | | Open flat, portrait | Regular width; sidebar should appear | | Open flat, landscape | Vertical bars active | | Partially folded | Division region active; nothing across the fold | | Propped on a table | Content readable at distance in the top region; controls reachable in the bottom | | Split View, various widths | Continuous reflow across the divider's full range | | Second scene open | Independent state in each window |
The transitions matter as much as the states. Most bugs surface while folding, not after. ## Automate the parts you can Snapshot tests at the two display sizes catch regressions cheaply once the layout is right: - Inner display: 626 × 890 points - Outer display: 466 × 678 points These will not catch division regions or pose-specific behaviour, so keep the manual pass for those. ## How to verify Walk the matrix above once per release on your primary flows. Record the pass so a regression later has something to compare against. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Run the App Resizability modernization skill in Xcode > Xcode 27.1 extends its app modernization skill to cover SwiftUI and iPhone Duo, automating part of the mechanical migration. Source: https://iphoneduosupport.com/checklist/app-resizability-skill/ Severity: polish Category: tooling Applies to: swiftui, uikit Requires: ios-27.1 SDK Symptom: Manually hunting through a large codebase for fixed sizes and deprecated screen references. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ Last verified: 2026-09-09 --- Apple's app modernization skill, previously "Modernize your UIKit app", now covers **SwiftUI and iPhone Duo** in Xcode 27.1 under the name **App Resizability**. ## Use it as a first pass It is good at the mechanical, high-volume work: finding fixed frame sizes, flagging main-screen references, surfacing symmetric safe-area math, pointing at code that will not resize. It cannot make design decisions. Whether a screen should become a split view, what belongs on the outer display, which actions deserve `.visibilityPriority(.high)` — those need judgement about your product. A sensible order: 1. Rebuild against the iOS 27.1 SDK. 2. Run App Resizability and review every change it proposes. 3. Work the blocker items on this checklist by hand. 4. Only then consider the new adaptive APIs — arrangements, reserved regions, scene accessories. ## Review its output rather than accepting it Automated fixes tend to be locally correct and globally bland. Replacing a fixed width with `maxWidth: .infinity` is right in a stack and wrong in a form field that now spans 626 points. Read each change with the surrounding layout in mind. ## How to verify After running the skill, build and walk the pose matrix. Treat its changes as a starting draft to review, not a completed migration. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Capacitor, Cordova and web views on iPhone Duo > Hybrid iOS apps adapt best to the foldable iPhone, because CSS was built for variable viewports. An analysis of the few things that still break. Source: https://iphoneduosupport.com/blog/capacitor-web-iphone-duo/ Published: 2026-09-09 Framework: capacitor Status: ENGINEERING ANALYSIS — this framework vendor has published no iPhone Duo guidance. Apple-side facts are sourced; framework-side conclusions are inference. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111466/ Last verified: 2026-09-09 --- Ionic has published no iPhone Duo guidance. This is our analysis of how a `WKWebView`-based iOS app behaves against the APIs and behaviours Apple documented on 9 September 2026. Hybrid apps have the easiest migration of any cross-platform stack, for a reason that has nothing to do with iPhone Duo: the web has assumed a variable viewport since the beginning. A well-built responsive layout adapts to a 626-point display without changes, because it has always had to adapt to everything else. The failures are concentrated in a handful of places where web code borrowed a native assumption. ## Opt into the display Environment variables report nothing useful until the web view claims the full display: ```html ``` Without `viewport-fit=cover`, `env(safe-area-inset-*)` resolves to zero and your layout is inset by the system with no way to draw underneath. This one line is a prerequisite for everything below. ## The one real break: symmetric insets If you fix nothing else, fix this. ```css /* Wrong on iPhone Duo — one value applied to both edges */ .container { padding: 0 env(safe-area-inset-left); } ``` Apple states safe areas are **asymmetric** on this device. Applying the left inset to both sides over-pads one edge, and content drifts visibly off-centre on a display wide enough that people notice. ```css .container { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); } ``` The shorthand form was harmless for a decade because the two values were always equal. Search your stylesheets for it specifically — it is the single highest-yield grep in a hybrid codebase: ```bash grep -rn "safe-area-inset" src/ ``` ## User-agent sniffing serves the wrong layout Any code branching on a phone user agent to pick a mobile layout will serve that layout on a regular-width, 626-point display with room for a sidebar. ```js // Wrong — iPhone Duo is an iPhone with a tablet-sized inner display const isMobile = /iPhone/.test(navigator.userAgent); ``` Media and container queries describe the space you actually have: ```css @media (min-width: 600px) { .layout { display: grid; grid-template-columns: 260px 1fr; } } ``` Container queries are better still where a component's own width matters more than the window's — which is often the case in Split View, where the window is smaller than the display: ```css @container (min-width: 480px) { .card { flex-direction: row; } } ``` ## Viewport units `100vh` has always been awkward on mobile. On iPhone Duo it gets worse, because the viewport changes while the app runs — folding, unfolding, and Split View resizing all change it without a navigation. ```css /* Fragile */ .screen { height: 100vh; } /* Tracks the dynamic viewport */ .screen { height: 100dvh; } ``` `dvh`, `svh`, and `lvh` all behave sensibly here. `vh` does not. ## JavaScript that measured once CSS reflows on its own. JavaScript that captured a dimension does not. ```js // Wrong — captured once const width = window.innerWidth; // Right const observer = new ResizeObserver(([entry]) => { layout(entry.contentRect.width); }); observer.observe(document.body); ``` `window.visualViewport` and its `resize` event are the other reliable signal, particularly when the keyboard is involved. A `window.resize` listener works too, but `ResizeObserver` is cheaper and fires for container changes that `window.resize` misses. This matters more than usual on iPhone Duo because resizes are frequent and user-initiated rather than rare and orientation-driven. ## What Capacitor gives you, and what it does not Capacitor's status bar and keyboard plugins behave normally. Nothing in the standard plugin set needs changing for this device. What has no web API at all: - Reserved regions — where the hinge divides the display - Hinge angle - Scene accessories — content on the outer display - The vertical toolbar region A Capacitor plugin wrapping the Swift APIs is entirely possible, and reserved regions would be the one worth building: a plugin that reports division-region frames as CSS custom properties would let a web layout avoid the fold with a `grid-template-columns` rule. Nobody has shipped this that we are aware of. For a typical content app, none of that is needed. The CSS-level adaptation above is the whole job. ## Aspect ratio The inner display is roughly 1.42 — close to √2, the A-series paper proportion. This is unusually good for the kind of layout hybrid apps tend to have: documents, feeds, lists, forms, article views. Two-column reading layouts fit it naturally. Embedded 16:9 video letterboxes, as it does everywhere else on this device. The web idiom of a fixed-aspect embed with content beneath it is already the pattern Apple recommends for native, so most hybrid apps need no change here. ## A pragmatic checklist 1. Confirm `viewport-fit=cover` is present 2. `grep -rn "safe-area-inset"` and split every shorthand into left and right 3. Replace user-agent layout branching with media and container queries 4. Swap `100vh` for `100dvh` 5. Replace cached `window.innerWidth` with `ResizeObserver` 6. Test the Split View divider through its full range 7. Consider a native plugin only if your app draws a full-bleed surface where the fold matters Steps 1 and 2 take an afternoon and account for nearly all of the visible difference. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Flutter on iPhone Duo: the right abstraction, possibly unwired > Flutter already has a foldable API from Android — MediaQuery.displayFeatures. An analysis of whether it reaches iPhone Duo, and what to do either way. Source: https://iphoneduosupport.com/blog/flutter-iphone-duo/ Published: 2026-09-09 Framework: flutter Status: ENGINEERING ANALYSIS — this framework vendor has published no iPhone Duo guidance. Apple-side facts are sourced; framework-side conclusions are inference. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111463/ Last verified: 2026-09-09 --- Google has published no iPhone Duo guidance. This is our analysis of how Flutter behaves against the APIs and behaviours Apple documented on 9 September 2026. Flutter is in a genuinely unusual position. It is the only major cross-platform framework that already has a **correct abstraction for foldables** — built years ago for Android devices — and the open question is not what the API should look like but whether it is connected on iOS. ## The abstraction Flutter already has `MediaQuery.displayFeatures` reports hinges and cutouts with bounds and state. It was designed for Android foldables and dual-screen devices, and the `TwoPane` widget was built on top of it. ```dart final features = MediaQuery.of(context).displayFeatures; final hinges = features.where((f) => f.type == DisplayFeatureType.hinge); ``` Conceptually this maps almost exactly onto Apple's model. Apple's **division regions** are hinges that split an area; Apple's **occlusion regions** are cutouts that cover one. Flutter's `DisplayFeatureType` already distinguishes those cases. Even the active/inactive distinction has an analogue in `DisplayFeatureState`. Someone designing a Flutter API for iPhone Duo from scratch would land close to what already exists. ## The open question Whether the iOS embedder populates `displayFeatures` from Apple's `reservedRegions` API is not something we can determine from Apple's material, and Flutter has announced nothing. **Assume it is empty until you have verified otherwise on a real build.** Log it early: ```dart @override Widget build(BuildContext context) { final features = MediaQuery.of(context).displayFeatures; debugPrint('displayFeatures on this device: $features'); // … } ``` If it is populated, the Android foldable patterns transfer directly and Flutter is in the best position of any cross-platform stack. If it is empty, you have the same options as React Native: a platform channel wrapping `reservedRegions(kind:)` and pushing frames into Dart, or fold-unaware but correct layout. Given how well the existing abstraction fits, a package filling this gap seems likely to appear — but nothing has been announced, and you should not plan around it. ## What works regardless Flutter's layout system is resolution-independent and adapts to any size. The core migration is the familiar discipline problem. **Read size in `build`, never cache it.** ```dart // Wrong — captured once, stale after the first fold late final double _width; @override void initState() { super.initState(); _width = MediaQuery.of(context).size.width; } // Right @override Widget build(BuildContext context) { final width = MediaQuery.sizeOf(context).width; return width > 600 ? const TwoColumn() : const SingleColumn(); } ``` `MediaQuery.sizeOf` is preferable to `MediaQuery.of(context).size` — it only rebuilds on size changes rather than on every MediaQuery change, which matters on a device where these change often. Use `LayoutBuilder` for decisions about a subtree's own constraints rather than the whole window. On iPhone Duo the difference is real, because Split View means the window is frequently smaller than the display. **Treat horizontal padding as two values.** Flutter has always exposed them separately, so this is easier here than in most stacks: ```dart final padding = MediaQuery.paddingOf(context); // padding.left and padding.right genuinely differ on iPhone Duo ``` Any code doing `padding.horizontal / 2`, or applying `EdgeInsets.symmetric(horizontal: padding.left)`, is asserting a symmetry that no longer holds. **Drop orientation as a layout strategy.** ```dart // This does not work on the inner display SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); ``` Apple states the inner display does not honor supported interface orientations. `OrientationBuilder` is similarly unhelpful — it tells you the aspect ratio, which on a 1.42 display is not the signal you want. Branch on width. ## The breakpoint you already have is probably right The inner display is 626 × 890 points, and Apple describes it as regular-width with room for a sidebar. Most Flutter apps already have a tablet breakpoint somewhere around 600 logical pixels. That breakpoint will now fire on an iPhone, and the layout behind it is very likely the correct one. Verify it is driven by size and not by platform: ```dart // Wrong — this is an iPhone final isTablet = defaultTargetPlatform == TargetPlatform.iOS && !isPhone; // Right final isWide = MediaQuery.sizeOf(context).width >= 600; ``` ## Aspect ratio and media The inner display's 1.42 ratio is much squarer than the roughly 2.17 of a current iPhone. A `Container` with `aspectRatio: 16/9` letterboxes heavily — fitted to width, a 16:9 video leaves around a fifth of the display as bars. Apple's own guidance is to use that space rather than fight it. In Flutter terms, a `Column` with the player at a fixed aspect and a list beneath it is the natural equivalent of an `ArrangementView` split — and it is a layout Flutter has always been able to express. For documents and feeds, 1.42 is close to √2, the A-series paper proportion. Page-shaped Flutter layouts fit this display unusually well. ## Split View and lifecycle All apps participate in side-by-side multitasking. Two things to test: - Drag the divider through its full range and confirm continuous reflow. `MediaQuery` handles it; cached values do not. - Check `AppLifecycleState` handling. In Split View your app can be visible but not resumed. Anything paused on `inactive` — video, animation controllers, timers — will look frozen to a user who can still see it. ## A pragmatic migration 1. Log `displayFeatures` on a real iPhone Duo build and find out where you stand 2. Replace cached `MediaQuery` reads with `sizeOf` in `build` 3. Audit `paddingOf` consumers for symmetric assumptions 4. Replace platform-based layout checks with width checks 5. Remove orientation preferences used as a layout strategy 6. Test the Split View divider and the lifecycle-pause path 7. Only then consider a platform channel for reserved regions Steps 2 to 5 are most of the visible improvement, and none of them depend on the answer to step 1. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # React Native on iPhone Duo: what breaks and what works > Meta has shipped no iPhone Duo support. Which React Native patterns break on the foldable display, which survive, and where a native module becomes unavoidable. Source: https://iphoneduosupport.com/blog/react-native-iphone-duo/ Published: 2026-09-09 Framework: react-native Status: ENGINEERING ANALYSIS — this framework vendor has published no iPhone Duo guidance. Apple-side facts are sourced; framework-side conclusions are inference. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111463/ https://developer.apple.com/videos/play/tech-talks/111464/ Last verified: 2026-09-09 --- Meta has not shipped iPhone Duo support and has published no guidance for it. Everything below is our analysis of how React Native behaves against the APIs and behaviours Apple documented on 9 September 2026. The Apple-side facts are sourced; the React Native conclusions are reasoned inference you should verify against your own build. The short version: React Native apps will mostly *work*, because flexbox is inherently adaptive. Three specific patterns break, and one capability is out of reach without native code. ## Why the baseline is better than you would expect Under the hood, a React Native view hierarchy is a native view hierarchy. When iPhone Duo unfolds, UIKit resizes the root view, and Yoga relayouts everything inside it. An app built with flex ratios rather than fixed pixel values adapts without a single line of change. That is genuinely most apps. Which makes the failures worth knowing precisely, because they are narrow. ## Break one: cached dimensions This is the big one, and it is nearly universal. ```jsx // Broken on iPhone Duo — evaluated once, at module load const { width } = Dimensions.get('window'); const styles = StyleSheet.create({ card: { width: width - 32 }, }); ``` That width was captured at launch. On iPhone Duo it becomes wrong when the user unfolds the device, folds it closed, rotates it, or resizes Split View. The style object is created once and never recomputed, so the card keeps its launch-time width forever. The fix is the hook, which re-renders on change: ```jsx function Card({ children }) { const { width } = useWindowDimensions(); return {children}; } ``` Worth searching for specifically, since the module-scope form is invisible in review: ```bash grep -rn "Dimensions.get" src/ ``` Every hit outside a component render is suspect. Note that `Dimensions.addEventListener` is a partial fix at best — it fires, but a `StyleSheet.create` object built at module load will not be rebuilt by it. There is a subtler variant worth checking: percentage-of-screen constants like `const CARD = width * 0.45`. These read as responsive and are not. ## Break two: orientation locking Many React Native apps lock to portrait, in `Info.plist` or through a library. Apple states the inner display **does not honor supported interface orientations**. So the lock silently stops working, and your app is laid out in configurations it was never designed for. If your layout assumed width is always less than height, that assumption is gone. The replacement is not another lock. It is a layout that works at any aspect ratio: ```jsx const { width, height } = useWindowDimensions(); const isWide = width > 600; return isWide ? : ; ``` A width of 600 is a reasonable dividing line here: the inner display is 626 points wide and the outer is 466. ## Break three: collapsed safe area insets `react-native-safe-area-context` reports the real insets. The problem is what application code does with them. ```jsx // Common, and now wrong const insets = useSafeAreaInsets(); ``` Apple is explicit that safe areas are **asymmetric** on iPhone Duo. Taking the max, or applying one horizontal value to both edges, was harmless when the two matched. It now over-pads one side, and content drifts off-centre. ```jsx ``` `SafeAreaView` handles this correctly on its own. The bugs are in hand-rolled inset math. ## What you cannot reach Here is the honest limitation. These have no JavaScript bindings today: - `ReservedRegion` — where the hinge divides the display - `ArrangementView` — pose-aware primary/secondary placement - `onHingeChange` — hinge angle - Scene accessories — content on the outer display while the app runs on the inner - The vertical toolbar APIs — `axisBehavior`, `visibilityPriority`, and the rest Reaching any of them means a native module wrapping the Swift API and bridging values into JS. For reserved regions that is a moderate piece of work: a native view that queries `reservedRegions(kind:)`, observes changes, and emits frames as props. **Until someone ships that, a React Native app can be correct on iPhone Duo but not hinge-aware.** It can lay out properly at any size; it cannot avoid placing a button on the fold. For most content apps — feeds, commerce, messaging, media — correctness is the whole job, and the fold falls in a place users tolerate. For a canvas, an editor, a drawing app, or a game board, the fold matters and you should budget for native work. ## What you get for free that is worth using The inner display is regular-width in both dimensions, with room for a sidebar. If your app has a tablet layout behind a breakpoint, it will now appear on a phone, and it is probably the right layout. Check that your breakpoint is driven by live dimensions rather than by a device-type check: ```jsx // Wrong — Platform.isPad is false on iPhone Duo const isTablet = Platform.OS === 'ios' && Platform.isPad; // Right const { width } = useWindowDimensions(); const isWide = width >= 600; ``` Any device-info library used to pick a layout has this same problem. ## Split View, and the freeze bug All apps participate in side-by-side multitasking on iPhone Duo — there is no opt-in. Two things to check: **Continuous resize.** Dragging the Split View divider changes your width continuously. `useWindowDimensions` handles it; cached values do not. **AppState.** In Split View your app can be visible but not active. Code that stops video, timers, or animation on `AppState` changing to `inactive` will look frozen to a user who can still see the window. This pattern is common in React Native for battery reasons, and it is worth revisiting for this device specifically. ## A pragmatic migration 1. `grep -rn "Dimensions.get"` — replace every module-scope call with `useWindowDimensions` 2. Remove orientation locks and fix whatever they were hiding 3. Audit `useSafeAreaInsets` consumers for symmetric math 4. Replace device-type layout checks with width checks 5. Test the Split View divider through its full range 6. Verify `AppState` handling does not freeze visible content 7. Decide whether the fold matters enough for a native module Steps 1 to 4 are a day's work in most codebases and account for nearly all of the visible improvement. ## What would change this analysis If React Native ships a `useDisplayFeatures`-style API bridging Apple's reserved regions, the last section becomes obsolete and hinge-aware layout becomes reachable in JS. Nothing has been announced. We will update this post if that changes — it is dated and versioned above. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # SwiftUI on iPhone Duo: adaptive layout and transitions > A walkthrough of the SwiftUI APIs for iPhone Duo — ArrangementView, ReservedRegion, size classes and vertical toolbars — in the order that actually works. Source: https://iphoneduosupport.com/blog/swiftui-iphone-duo-adaptive-layout/ Published: 2026-09-09 Framework: swiftui Status: Apple-documented — every claim traces to an Apple source. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111463/ https://developer.apple.com/videos/play/tech-talks/111462/ https://developer.apple.com/videos/play/tech-talks/111466/ Last verified: 2026-09-09 --- Apple's six iPhone Duo Tech Talks contain a lot of API surface, and the natural reaction is to start adopting the new things. That is the wrong order. Most of what makes a SwiftUI app look wrong on iPhone Duo is old code making assumptions that were safe until 9 September 2026 — and until those are gone, the new APIs are built on sand. Here is the order that actually works. ## First: understand what you already have Your existing app runs on iPhone Duo today, without changes. Apple defined three tiers of behaviour, and which one you get depends entirely on the SDK you build against:
| Built against | Inner display behaviour | | --- | --- | | Not the iOS 27 SDK | Familiar size and aspect ratio | | iOS 27 SDK | Extends left of the status bar area | | iOS 27.1 SDK | Extends to the screen edge; bar buttons lay out vertically |
Tier one is not broken. It is an app that does not use the display. That is a competitive problem, not a support ticket — which matters when you are deciding how much time to spend. The catch is that moving to tier three makes you responsible for the geometry you just claimed: the hinge, the asymmetric safe areas, the vertical bars. Rebuild against 27.1 and stop there and you can genuinely end up looking worse than before. ## Second: delete the assumptions Four assumptions were true on every iPhone before this one. **"The screen is about 400 points wide."** The inner display is 626 × 890 points. Not 20% wider — over 50%. ```swift // Before content.frame(width: 390) // After content .frame(maxWidth: .infinity) .frame(maxWidth: 700) // cap for readability, not for a device ``` **"Portrait means tall."** The inner display does not honor supported interface orientations. If you locked to portrait, you are still going to be laid out in landscape. ```swift @Environment(\.horizontalSizeClass) private var horizontalSizeClass var body: some View { if horizontalSizeClass == .regular { WideLayout() } else { NarrowLayout() } } ``` The inner display is **regular in both dimensions**, and Apple notes it leaves room for sidebars. The outer display is compact-width, regular-height. If you have an iPad layout, the inner display usually wants it. **"Left and right insets match."** They do not, on this device. This is the one that produces subtly off-centre layouts that nobody can quite explain: ```swift // Wrong let width = bounds.width - insets.left * 2 // Right let width = bounds.inset(by: insets).width ``` **"Idiom tells me the screen size."** iPhone Duo reports `.phone` with a regular-width display. Every `if idiom == .pad` gate now hides your good layout on the device that most needs it. Fix these four and most apps are already respectable. Everything below is upside. ## Third: adopt arrangements `ArrangementView` is the API worth real investment. It takes a primary and secondary view and places them across every pose, using size classes, aspect ratio, and the active division regions as input. ```swift var body: some View { NavigationStack { ArrangementView { PlayerView() } secondary: { UpNextView() } .arrangementViewStyle(.split) } } ``` Split splits horizontally when the view is wider than tall and vertically when taller. Pin the axis when only one makes sense: ```swift .arrangementViewStyle(.split.axes(.horizontal)) ``` Overlay is for a foreground/background relationship rather than a peer one. Its secondary view should respond to its own depth: ```swift struct UpNextView: View { @Environment(\.overlayArrangementZIndex) private var zIndex: Int var minimization: UpNextMinimization { zIndex > 0 ? .collapsed : .expanded } } ``` Apple describes a third pattern, **displacement** — moving elements as space changes — and warns against it for continuously scrolling content. Shifting a feed under the reader's thumb is disorienting. One column that changes width beats a column that moves. ### Why this beats writing it yourself The obvious alternative is a `GeometryReader` with your own breakpoints. It works, until you count the states: two displays, four-plus poses, arbitrary Split View widths, multiple scenes, and a hinge that appears and disappears. `ArrangementView` handles that matrix, and will handle whatever ships next. ## Fourth: handle the fold `ReservedRegion` reports where the display is interrupted. Two kinds, and the difference matters: ```swift GeometryReader { proxy in let division = proxy.reservedRegions(kind: .division) // the hinge let occlusion = proxy.reservedRegions(kind: .occlusion) // the inner camera } ``` A division region **divides** an area in two. An occlusion region **covers** part of one. The hinge is the first; the under-display FaceTime camera is the second. The behavioural detail that catches people: a division region is active only while the device is folded, and has **zero width when flat**. Your layout must handle regions appearing and disappearing, not just moving. To lay out ahead of a fold and avoid a jump: ```swift let regions = proxy.reservedRegions(kind: .division, options: .includeInactive) ``` Use arrangements where they fit and query regions directly only when you need finer control — a canvas, a game board, a photo editor. ## Fifth: the vertical bar Under the 27.1 SDK, navigation, toolbar, and tab bar controls share a single vertical region on the inner display in landscape. Standard containers do this for free. What needs your attention is content. A column has far less room for a label than a row. Apple's guidance is to prefer symbol-only items and minimise text-only and custom dual-content views. Order matters too — navigation at the top, prominent actions at the bottom: ```swift .toolbar { ToolbarItem(placement: .cancellationAction) { CloseButton() } ToolbarItem(placement: .topBarPinnedTrailing) { ShareButton() } } ``` Say which of your actions must survive: ```swift ToolbarItem { ComposeButton() }.visibilityPriority(.high) ``` Reserve `.high` for the few actions users reach for constantly — marking everything high is the same as marking nothing. Some items read badly rotated, and `axisBehavior` handles those: ```swift .axisBehavior(.horizontalOnly) ``` You can opt a screen out entirely. Apple names calculators and minimal sheets as good candidates: ```swift .toolbarVerticalBehavior(.disabled) ``` Do that per screen, deliberately. Doing it globally to avoid the work will look exactly like what it is. ## Sixth: the finishing touches Let background art bleed and keep interactive content inside the safe area: ```swift BackgroundArtwork().ignoresSafeArea() ``` Follow the screen's rounded corners without hard-coding a radius: ```swift ConcentricRectangle() .fill(.green) .padding(8.0) .ignoresSafeArea() ``` And one modifier that is close to free value: ```swift TabView { … }.defaultTabBarPlacement(.sidebar) ``` A five-item tab bar stretched across 626 points looks lost. A sidebar looks designed. ## On transitions A question worth addressing directly, since it is what people search for: there is no special "fold transition" API to adopt. The fold is not an animation you drive — it is a size and trait change, and SwiftUI already animates those. What makes a fold feel good is that your layout is a **pure function of the size it is given**. When that holds, SwiftUI interpolates between the two states on its own and the result looks intentional. When it does not — when layout is computed imperatively in a callback, or cached, or driven by hinge angle — you get a jump or a jitter that no animation modifier will fix. Which is why hinge angle is explicitly *not* for layout. Apple's line is that hinge data is for interactions and effects only: ```swift GuitarView(pitchBend: pitchBend) .onHingeChange { _, context in if let hinge = context.hinge, hinge.status == .partiallyOpen { pitchBend = calculatePitchBend(angle: hinge.angle) } else { pitchBend = 0 } } ``` Angle is continuous and noisy; layout driven by it shivers. Division regions are discrete and stable, which is what layout wants. Use angle for what it is uniquely good at: a continuous input to an effect. ## Verifying Xcode 27.1 ships an iPhone Duo simulator in Device Hub with on-screen controls to open, close, rotate, and fold. Walk every pose, and pay attention to the *transitions* — most bugs surface while folding rather than after. Snapshot tests at 626 × 890 and 466 × 678 catch regressions cheaply once the layout is right. They will not catch division regions, so keep a manual pass for those. ## The order, condensed 1. Rebuild against the iOS 27.1 SDK 2. Run the App Resizability skill, review every change 3. Delete the four assumptions: fixed widths, orientation, symmetric insets, idiom 4. Adopt `ArrangementView` where you have a primary/secondary relationship 5. Query reserved regions only where arrangements are not enough 6. Audit toolbar content for the vertical bar 7. Concentric corners, sidebar tab bar, background bleed Steps 1 and 3 are most of the visible improvement. The rest is what separates an app that works from one that looks like it was designed for this device. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # UIKit on iPhone Duo: vertical bars and arrangements > What changes in a UIKit app on iPhone Duo: the vertical bar region, UIArrangementViewController, reserved regions, and the UIScreen.main deprecation. Source: https://iphoneduosupport.com/blog/uikit-iphone-duo-vertical-bars/ Published: 2026-09-09 Framework: uikit Status: Apple-documented — every claim traces to an Apple source. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111462/ https://developer.apple.com/videos/play/tech-talks/111463/ Last verified: 2026-09-09 --- UIKit apps have an advantage on iPhone Duo that is easy to miss: if your app already supports iPad, most of the work is done. The inner display is regular-width in both dimensions, which is the same environment your iPad layout already targets. The apps with real work ahead are iPhone-only ones, and apps that replaced the system bars with their own. ## UIScreen.main stops making sense Start here, because it is the change with the widest blast radius. Apple stated in *Prepare your app for iPhone Duo* that main screen references will be deprecated and should be avoided on two-display devices. This is not a style preference. iPhone Duo has two displays with **different pixel densities** — 430 ppi inner, 460 ppi outer — and your app can move between them while running. A global "main screen" cannot answer which display a given view is actually on. ```swift // Before let scale = UIScreen.main.scale let bounds = UIScreen.main.bounds // After let scale = traitCollection.displayScale let screen = view.window?.windowScene?.screen ``` Scale is a trait, so it updates automatically as the view moves between displays. That is the whole point of reading it from the trait collection rather than a global. For layout, do not reach for the screen at all. `view.bounds` and the safe area describe the space you were given — which in Split View is smaller than the display regardless of which one you are on. ```bash grep -rn "UIScreen.main" --include="*.swift" . ``` Run that first. It is usually a bigger list than people expect, and much of it is in code nobody has opened in years. ## Safe areas are asymmetric On every previous iPhone, left and right insets were mirror images. That made a shortcut look safe: ```swift // Wrong on iPhone Duo let width = view.bounds.width - view.safeAreaInsets.left * 2 ``` The status bar and camera sit asymmetrically on the inner display, and the hinge introduces geometry with no mirror. Inset the rectangle instead of doing arithmetic on one side: ```swift let width = view.bounds.inset(by: view.safeAreaInsets).width ``` Apple's split is worth stating plainly, because it is what makes an app look finished: ```swift // Interactive content — inside the safe area foreground.frame = view.bounds.inset(by: view.safeAreaInsets) // Background artwork — full bounds backgroundView.frame = view.bounds ``` Applying one policy to a whole screen is the mistake. A card with a background image wants the image to bleed and the text to stay inset. ## The vertical bar region This is the most visible change under the iOS 27.1 SDK. On the inner display in landscape, navigation, toolbar, and tab bar controls move into a **single shared vertical region** at the side. Picture your bars rotated ninety degrees into one column. You get this automatically with `UINavigationController` and `UITabBarController`. **Custom `UIToolbar` content is not considered.** If you replaced the system bars with your own — a common decision in apps with strong visual identity — you are outside the adaptive path and will need to rebuild on the system containers to get back into it. Two details worth knowing: the bar stays on the same side in right-to-left languages, and in a split view only the detail column participates. Inspectors do not get their own bar. ### Controlling it Placement, since order matters in a column: ```swift // Back / close goes to the top navigationItem.leftBarButtonItem = closeItem // .cancellationAction equivalent ``` Orientation of individual items: ```swift item.axisBehavior = .verticalPreferred item.axisBehavior = .horizontalOnly ``` Detecting the vertical case, so custom views can adapt: ```swift switch traitCollection.verticalBarEdge { … } ``` What compresses first when space runs out: ```swift navigationItem.verticalBarCompressionBehavior = .prefersBarItems ``` Which actions survive overflow: ```swift item.visibilityPriority = .high ``` And consolidating your own ellipsis menu into the system one, so users do not see two identical menus stacked: ```swift navigationItem.additionalOverflowItems = UIDeferredMenuElement({ provider in provider(self.persistentOverflowItems()) }) ``` Badges from iOS 26 carry over, and are useful for keeping a signal on an item that has lost its text label: ```swift item.badge = .count(7) ``` ### Opting out Some screens are worse for it. Apple names single-page layouts with heavy bottom content — a calculator — and sheets with only a close button: ```swift override var preferredVerticalBarBehavior: UIVerticalBarBehavior { .disabled } ``` Per screen, on purpose. Not globally. ## Arrangements `UIArrangementViewController` is the UIKit counterpart to SwiftUI's `ArrangementView`, and it handles the main-and-secondary case across every pose: ```swift let arrangementVC = UIArrangementViewController() let navController = UINavigationController(rootViewController: arrangementVC) arrangementVC.setViewController(PlayerViewController(), for: .primary) arrangementVC.setViewController(UpNextViewController(), for: .secondary) ``` Style is set the same way, and can be updated at runtime: ```swift arrangementVC.updateArrangement(.split.axes(.horizontal)) ``` For an overlay arrangement, read the z-index so the secondary view can collapse when stacked: ```swift let primaryState = arrangementVC.state(for: .primary) myModel.minimization = (primaryState?.zIndex ?? 0) > 0 ? .collapsed : .expanded ``` ## Reserved regions `UIViewReservedRegion` reports where the display is interrupted: ```swift let regions = view.reservedRegions(kind: .division) let frames = regions.map(\.frame) ``` Division regions divide — the hinge. Occlusion regions cover — the under-display camera. Division regions are **active only while folded and have zero width when flat**, so handle them appearing and disappearing, not just moving. Use arrangements first. Query regions directly when you need control an arrangement cannot give you. ## Multiple scenes iPhone Duo is the first iPhone supporting multiple app instances. Apps already supporting this on iPad get it here. ```xml UIApplicationSupportsMultipleScenes ``` Two constraints: new windows can only be created on the **inner display**, and Apple is explicit that you **must handle errors** when requesting a scene through `UIWindowSceneActivation`. The action hides itself when windows are unavailable, so a correctly built UI does not offer something that cannot work. If you enable it, audit anything assuming a single instance — singletons holding view state, global notification handling that presents UI, analytics assuming one session per launch. ## Split View is not optional All apps participate in side-by-side multitasking on iPhone Duo. An app that has never been resized can now be handed an arbitrary fraction of the display, at a moment the user chooses. ```swift override func viewWillTransition( to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator ) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate { _ in self.relayout(for: size) } } ``` While you are there, check `UIRequiresFullScreen`. An app still carrying that key is fighting the platform. One failure mode that is easy to miss: in Split View your app can be **visible but not frontmost**. Timers, video, and animation stopped on `sceneWillResignActive` will look frozen to a user who can still see the window. ## Where to start 1. `grep -rn "UIScreen.main"` and fix every hit 2. `grep -rn "userInterfaceIdiom"` and check each one against size classes instead 3. Rebuild against the iOS 27.1 SDK 4. Run the App Resizability skill in Xcode 27.1 — it now covers this migration 5. Audit bar content for the vertical region 6. Adopt `UIArrangementViewController` where you have a primary/secondary screen Steps 1 and 2 are unglamorous and account for most of the difference between an app that behaves and one that does not. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Unity games on iPhone Duo: resolution changes mid-play > Games have a harder iPhone Duo problem than apps, because resolution is usually treated as a launch-time constant. An analysis of what changes in a Unity iOS build. Source: https://iphoneduosupport.com/blog/unity-iphone-duo-games/ Published: 2026-09-09 Framework: unity Status: ENGINEERING ANALYSIS — this framework vendor has published no iPhone Duo guidance. Apple-side facts are sourced; framework-side conclusions are inference. Sources: https://developer.apple.com/videos/play/tech-talks/111461/ https://developer.apple.com/videos/play/tech-talks/111466/ https://developer.apple.com/videos/play/tech-talks/111464/ Last verified: 2026-09-09 --- Unity has shipped no iPhone Duo support. This is our analysis of how a Unity iOS build behaves against the APIs and behaviours Apple documented on 9 September 2026. Games have a harder problem than apps here. An app is built from views that expect to be resized. A game usually renders to a surface whose dimensions were read once at startup and treated as fixed for the session. On iPhone Duo, they are not. ## Resolution changes while the game is running `Screen.width` and `Screen.height` now change mid-session: when the device is folded or unfolded, when the app moves between the inner and outer displays, and when Split View is resized by the user. Anything cached in `Start()` is stale from that moment. That typically includes camera viewport rects, canvas scaler reference resolutions, render textures, and any world-to-screen maths. ```csharp int _lastW, _lastH; void Start() { _lastW = Screen.width; _lastH = Screen.height; } void Update() { if (Screen.width != _lastW || Screen.height != _lastH) { _lastW = Screen.width; _lastH = Screen.height; OnResolutionChanged(); } } void OnResolutionChanged() { // Rebuild render targets, recompute viewport rects, refresh UI anchors } ``` Polling is unglamorous but reliable, and the check is cheap. The alternative — assuming a resolution change implies a scene reload — does not hold here, because the player can fold the device mid-level. Render textures are the expensive case. Reallocating every frame during a fold animation will hitch, so debounce: wait for dimensions to settle for a few frames before reallocating. ## Safe area `Screen.safeArea` is the right API and it works correctly. The trap is the same one native apps hit: ```csharp // Wrong — asserts the two sides match float margin = Screen.safeArea.x; rect.offsetMin = new Vector2(margin, rect.offsetMin.y); rect.offsetMax = new Vector2(-margin, rect.offsetMax.y); // Right — use the rect as given Rect safe = Screen.safeArea; rect.anchorMin = new Vector2(safe.x / Screen.width, safe.y / Screen.height); rect.anchorMax = new Vector2((safe.x + safe.width) / Screen.width, (safe.y + safe.height) / Screen.height); ``` Apple states safe areas are asymmetric on iPhone Duo, so any single-margin derivation is wrong on at least one edge. Note that `Screen.safeArea` must be re-read after every resolution change, alongside everything else. ## Aspect ratio is the design decision The inner display is roughly **1.42**. Most mobile games are tuned for something near 2.17. That gap is large enough to be a design decision rather than a scaling parameter. Two honest options, and they should be chosen per scene: **Letterbox to a fixed aspect.** Predictable, safe, and preserves your composition exactly. On a 1.42 display it leaves substantial bars — around a fifth of the screen for 16:9 content. For a game with hand-authored levels tuned to a specific frame, this is often correct. **Extend the camera frustum.** Fills the display, but shows more of the world than the level was designed to reveal. For a 2D platformer this can expose off-screen enemies or unbuilt geometry. For a 3D game with a full environment it is usually free. The version to avoid is scaling to fill with a fixed aspect, which crops around a quarter of the frame width. In a game where the edges carry information — a HUD, an enemy indicator, a minimap — that is a functional regression, not a cosmetic one. ## The hinge Division regions have no Unity binding. Reaching them means a native plugin wrapping `reservedRegions(kind:)` and marshalling frames into C#. That is real work, and for most games there is a cheaper mitigation that captures most of the benefit: **keep critical HUD elements out of the horizontal centre band** when running on a foldable. You cannot know exactly where the fold is without the native API, but you know roughly where it is, and moving a health bar away from centre is a five-minute change. For a game where the fold is genuinely part of the experience — a board game across the crease, a two-player mode with the device propped — the plugin is worth building. For a runner or a puzzle game, it is not. ## Lifecycle: the freeze bug This is the failure most likely to reach players. Folding the device can move your app between displays **without backgrounding it**, and in Split View your game can be visible but not frontmost. A common Unity pattern is: ```csharp void OnApplicationPause(bool paused) { Time.timeScale = paused ? 0f : 1f; } ``` On iPhone Duo that can leave a visibly frozen game on screen. Test folding and unfolding during **active play**, not from a paused menu — and consider distinguishing "not frontmost but visible" from "backgrounded" before stopping simulation. ## Input Touch coordinates are reported in the current screen space, so they follow resolution changes automatically. What does not follow is any input region computed from cached dimensions — virtual joystick bounds, tap zones, swipe thresholds expressed in pixels. Recompute these in `OnResolutionChanged` along with everything else. ## A pragmatic checklist 1. Add a resolution-change detector and route all screen-derived state through it 2. Re-read `Screen.safeArea` on that event; use the rect, not a single margin 3. Decide letterbox versus extended frustum, per scene, deliberately 4. Test folding during active play and fix any pause-driven freeze 5. Recompute input regions on resolution change 6. Move critical HUD out of the centre band 7. Consider a native plugin only if the fold is part of the design Items 1 and 4 are the ones players will notice. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # SwiftUI on iPhone Duo > SwiftUI has first-party iPhone Duo support. ArrangementView, ReservedRegion and the vertical toolbar APIs ship in the iOS 27.1 SDK. Source: https://iphoneduosupport.com/frameworks/swiftui/ Support status: first-party Apple ships the adaptive APIs directly. Most SwiftUI apps need configuration and layout review rather than rewriting. Last verified: 2026-09-09 --- SwiftUI is the best-supported way to build for iPhone Duo. Declarative layout already recomputes when the available size changes, so a SwiftUI app that avoids fixed sizes gets much of the adaptation for free. ## What you get without changes Build against the iOS 27.1 SDK and the following already adapt: `NavigationSplitView`, `TabView`, sheets, popovers, context menus, and alerts. Columns collapse when the device is closed and tile or overlay when it is open. Standard navigation and toolbar buttons move into a vertical bar on the inner display in landscape. ## What you need to change The work concentrates in four places: 1. **Fixed sizes.** Any `.frame(width:)` tuned for a 402-point iPhone is wrong on a 626-point display. See [hard-coded screen dimensions](/checklist/hardcoded-screen-dimensions/). 2. **Orientation logic.** The inner display does not honor supported interface orientations. Move to `@Environment(\.horizontalSizeClass)`. See [size classes](/checklist/size-classes-not-orientation/). 3. **Safe area math.** Insets are asymmetric now. See [asymmetric safe areas](/checklist/asymmetric-safe-area-insets/). 4. **Toolbar content.** A vertical bar holds fewer items. See [overflow priorities](/checklist/toolbar-overflow-priority/). ## The new APIs worth adopting `ArrangementView` is the highest-value addition — it places a primary and secondary view across every pose, taking size classes, aspect ratio, and active division regions as input: ```swift ArrangementView { PlayerView() } secondary: { UpNextView() } .arrangementViewStyle(.split) ``` `ReservedRegion` reports where the hinge divides the display and where the under-display camera occludes it: ```swift GeometryReader { proxy in let regions = proxy.reservedRegions(kind: .division) } ``` And one modifier that is close to free: ```swift TabView { … }.defaultTabBarPlacement(.sidebar) ``` Read the full walkthrough in [SwiftUI on iPhone Duo](/blog/swiftui-iphone-duo-adaptive-layout/). --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # UIKit on iPhone Duo > UIKit has full first-party iPhone Duo support, with UIArrangementViewController, UIViewReservedRegion and vertical bar APIs in the iOS 27.1 SDK. Source: https://iphoneduosupport.com/frameworks/uikit/ Support status: first-party Every SwiftUI capability has a UIKit counterpart. Apps built on standard containers adapt with little work. Last verified: 2026-09-09 --- UIKit is fully supported on iPhone Duo, and every SwiftUI adaptive API has a UIKit counterpart. Apps built on `UINavigationController`, `UITabBarController`, and `UISplitViewController` get most of the adaptation automatically. ## What adapts automatically Standard containers are fully adaptive across all poses. Custom `UIToolbar` content is **not** considered for vertical bar placement, so an app that replaced the system bars with its own has more work than one that did not. ## The main migrations `UIScreen.main` is being deprecated on two-display devices. Read scale from traits and the screen from the window scene: ```swift let scale = traitCollection.displayScale let screen = view.window?.windowScene?.screen ``` Safe area insets are asymmetric, so inset the rectangle rather than doubling one side: ```swift let width = view.bounds.inset(by: view.safeAreaInsets).width ``` Audit `userInterfaceIdiom` checks. iPhone Duo reports the phone idiom with a regular-width display, so idiom-gated iPad layouts never appear. See [idiom assumptions](/checklist/idiom-based-assumptions/). ## The new UIKit APIs ```swift let arrangementVC = UIArrangementViewController() arrangementVC.setViewController(playerVC, for: .primary) arrangementVC.setViewController(upNextVC, for: .secondary) ``` ```swift let regions = view.reservedRegions(kind: .division) ``` For vertical bars, `item.axisBehavior`, `traitCollection.verticalBarEdge`, `navigationItem.verticalBarCompressionBehavior`, and `preferredVerticalBarBehavior` control placement, adaptation, compression, and opt-out respectively. Start with the **App Resizability** modernization skill in Xcode 27.1, which now covers this migration. See [UIKit on iPhone Duo](/blog/uikit-iphone-duo-vertical-bars/). --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # React Native on iPhone Duo > React Native has shipped no iPhone Duo support. Core layout works, but the new adaptive APIs need a native module and several common patterns break. Source: https://iphoneduosupport.com/frameworks/react-native/ Support status: none No first-party support. Flexbox layout adapts, but cached dimensions, orientation locking and safe-area assumptions all need attention. Last verified: 2026-09-09 --- Meta has not shipped iPhone Duo support and has published no guidance for it. What follows is our analysis of how React Native behaves against Apple's documented behaviours. ## The good news Flexbox is inherently adaptive. A React Native layout built with flex ratios rather than fixed pixel values reflows correctly on the inner display without changes, because the native view hierarchy is resized by UIKit underneath. ## What breaks **Cached dimensions.** `Dimensions.get('window')` read once at module scope is the single most common failure. It captures a size that changes when the device folds, rotates, or enters Split View. Use the hook, which re-renders on change: ```jsx const { width, height } = useWindowDimensions(); ``` **Orientation locking.** Locking to portrait in `Info.plist` or through a library does not work on the inner display, which ignores supported interface orientations. Your app will be laid out in configurations you did not design. **Safe area assumptions.** `react-native-safe-area-context` reports real insets, but application code frequently collapses them — taking the larger of left and right, or applying one horizontal padding value to both sides. Those insets are now genuinely different. Apply `insets.left` and `insets.right` separately. **Fixed dimension styles.** `width: 390` and `Dimensions.get('window').width * 0.5` computed at render-time-once have the same problem as native fixed frames. ## What is unreachable today `ReservedRegion`, `ArrangementView`, hinge angle, scene accessories, and the vertical bar APIs have no JavaScript bindings. Reaching them requires a native module wrapping the Swift API and bridging values into JS. Until someone ships that, a React Native app can be *correct* on iPhone Duo but cannot be *hinge-aware* — it cannot avoid placing content across the fold. For most apps correctness is enough. For a canvas, editor, or game where the fold matters, budget for native work. Full analysis: [React Native on iPhone Duo](/blog/react-native-iphone-duo/). --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Flutter on iPhone Duo > Flutter has mature foldable support on Android through MediaQuery.displayFeatures, but nothing equivalent has shipped for iPhone Duo on iOS. Source: https://iphoneduosupport.com/frameworks/flutter/ Support status: partial The abstraction already exists from Android foldables. Whether the iOS embedder populates it for iPhone Duo is unconfirmed. Last verified: 2026-09-09 --- Flutter is in an unusual position: it already has the *right abstraction* for foldables, built for Android devices years ago, but no confirmation that it is wired up on iOS for iPhone Duo. Google has published no iPhone Duo guidance. What follows is our analysis. ## The abstraction already exists `MediaQuery.displayFeatures` reports hinges and cutouts on Android foldables, with bounds and state, and the `TwoPane` widget and hinge-aware widgets were built on top of it. Conceptually this maps almost exactly onto Apple's division and occlusion regions. ```dart final features = MediaQuery.of(context).displayFeatures; final hinge = features.where((f) => f.type == DisplayFeatureType.hinge); ``` ## The open question Whether the iOS embedder populates `displayFeatures` from Apple's `reservedRegions` API is not something we can confirm from Apple's material, and Flutter has announced nothing. Until it does, **assume `displayFeatures` is empty on iPhone Duo** and verify on a real build before relying on it. If it turns out to be unpopulated, the same options apply as for React Native: a platform channel wrapping the Swift API, or accept fold-unaware but correct layout. ## What works regardless Flutter's layout system is resolution-independent and adapts to any size, so the core migration is the familiar one: - Read `MediaQuery.sizeOf(context)` in `build`, never cache it in `initState` - Use `LayoutBuilder` for local size decisions - Treat `MediaQuery.paddingOf(context).left` and `.right` as **different values** — Flutter has always exposed them separately, so this is a discipline problem rather than an API problem - Drop `SystemChrome.setPreferredOrientations` as a layout strategy; the inner display ignores it Since the inner display is regular-width in both dimensions, the tablet breakpoints most Flutter apps already have are usually the right layout to serve. Full analysis: [Flutter on iPhone Duo](/blog/flutter-iphone-duo/). --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Unity on iPhone Duo > Unity games face resolution changes mid-session on iPhone Duo, plus safe-area and pause-behaviour issues that a fixed-resolution game has never handled. Source: https://iphoneduosupport.com/frameworks/unity/ Support status: none No first-party support. Screen.safeArea works, but mid-session resolution changes and fold-driven lifecycle events need explicit handling. Last verified: 2026-09-09 --- Unity has shipped no iPhone Duo support. What follows is our analysis of how a Unity iOS build behaves against Apple's documented behaviours. Games have a harder problem than apps here, because a game usually renders to a fixed-aspect surface and treats resolution as a launch-time constant. ## Resolution changes while running On iPhone Duo, `Screen.width` and `Screen.height` change during play — when the device is folded or unfolded, when the app moves between displays, and when Split View is resized. Anything cached at `Start()` is stale from that moment. ```csharp // Poll for changes rather than caching once void Update() { if (Screen.width != _lastW || Screen.height != _lastH) { _lastW = Screen.width; _lastH = Screen.height; RebuildLayout(); } } ``` Camera viewport rects, canvas scalers, and any render texture sized from screen dimensions all need recomputing on that event. ## Safe area `Screen.safeArea` is the right API and it works. The trap is the same as native: code that takes one horizontal inset and applies it to both edges. On iPhone Duo the two differ, so use the rect directly rather than deriving a single margin from it. ## Aspect ratio The inner display is roughly 1.42 — much squarer than the 2.17 most mobile games are tuned for. A game that letterboxes to a fixed aspect will leave large bands; one that extends the camera frustum will show more of the world than the level was designed to reveal. Decide which, deliberately, per scene. ## Lifecycle Folding the device can move your app between displays without backgrounding it. A game that pauses on `OnApplicationPause` and resumes only on explicit focus can appear frozen. Test fold and unfold during active play, not just from a menu. ## Reserved regions The hinge division region has no Unity binding. Reaching it requires a native plugin wrapping the Swift API. For most games the practical mitigation is simpler: keep critical HUD elements away from the horizontal centre band of the screen when running on a foldable. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # Capacitor & web views on iPhone Duo > Web-based iOS apps adapt well to iPhone Duo if they use CSS environment variables correctly and treat the viewport as genuinely variable. Source: https://iphoneduosupport.com/frameworks/capacitor/ Support status: none No framework-specific support needed for most cases. CSS handles the adaptation; asymmetric safe-area insets are the main trap. Last verified: 2026-09-09 --- Capacitor, Cordova, and hybrid apps built on `WKWebView` are in the strongest position of any cross-platform stack, because CSS was designed for variable viewports from the start. Ionic has published no iPhone Duo guidance; what follows is our analysis. ## Enable the safe area The web view must opt into the full display before environment variables report anything useful: ```html ``` ## Treat left and right insets as different This is the one place where existing web code reliably breaks. A common shorthand is: ```css /* Wrong on iPhone Duo — assumes the two sides match */ padding: 0 env(safe-area-inset-left); ``` Apple's safe areas are asymmetric on this device, so apply each side explicitly: ```css padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); ``` ## Use container queries, not user-agent sniffing Any code branching on a phone user agent to pick a mobile layout will serve that layout on a 626-point regular-width display. Container and media queries describe the space you actually have: ```css @media (min-width: 600px) { .layout { grid-template-columns: 260px 1fr; } } ``` ## Handle the resize `WKWebView` resizes when the device folds and when Split View changes. Layout driven by CSS handles this on its own; JavaScript that measured the viewport once does not. Prefer `ResizeObserver` and `visualViewport` events over a cached `window.innerWidth`. Avoid `100vh` for full-height layouts — it behaves poorly when the viewport changes under you. `100dvh` tracks the dynamic viewport correctly. ## What is out of reach Reserved regions, hinge angle, and scene accessories have no web API. A Capacitor plugin wrapping the Swift APIs is possible, but for a typical content app the CSS-level adaptation above is the whole job. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # iPhone Duo developer glossary > Definitions of the iPhone Duo developer vocabulary. Source: https://iphoneduosupport.com/glossary/ --- ## App Resizability The Xcode 27.1 app modernization skill, previously named Modernize your UIKit app, now extended to cover SwiftUI and iPhone Duo. It automates part of the mechanical migration work such as finding fixed sizes and deprecated screen references. ## Arrangement A layout container that places a primary and a secondary view across iPhone Duo's poses, using size classes, the view's aspect ratio and active division regions as input. Available as ArrangementView in SwiftUI and UIArrangementViewController in UIKit, with split and overlay styles. ## Axis behavior A property controlling whether a bar item orients vertically when placed in a vertical bar, or stays horizontal regardless. Set with .axisBehavior(.verticalPreferred) or .horizontalOnly in SwiftUI and item.axisBehavior in UIKit. ## Device Hub The Xcode 27.1 simulator interface for iPhone Duo, with on-screen control buttons to open, close, rotate and fold the device so a layout can be checked in every pose. ## Division region A reserved region that divides the iPhone Duo inner display into separate usable areas. The hinge is the example: it is active only while the device is folded and has zero width when the device is flat. ## Hinge angle The physical angle of the iPhone Duo hinge, reported through onHingeChange in SwiftUI and UIHingeInteraction in UIKit, with states closed, partially open and fully open. Apple's guidance is to use it for interactions and effects only, never for layout decisions. ## Multiple scenes Support for more than one instance of an app at once, declared with UIApplicationSupportsMultipleScenes. iPhone Duo is the first iPhone to support this. New windows can only be created on the inner display; the outer display is reserved. ## Occlusion region A reserved region that covers part of the display rather than dividing it. On iPhone Duo the under-display FaceTime camera on the inner display is an occlusion region. Background content may pass beneath one; interactive content should not. ## Pose A physical configuration of iPhone Duo — closed, partially folded like a book, propped on a table, or fully open flat — each combined with an orientation. Xcode's Device Hub simulates poses with on-screen controls to open, close, rotate and fold. ## Reserved region An area of the screen that system hardware or UI claims, reported by ReservedRegion in SwiftUI and UIViewReservedRegion in UIKit from iOS 27.1. Regions come in two kinds — division and occlusion — and each has an active and an inactive state. ## Safe area The region of a view not covered by system UI. On iPhone Duo safe areas and layout margins are asymmetric, so each side must be handled independently — code that doubles one inset to account for the opposite side is wrong on this device. ## Scene accessory Supplementary UI shown on one iPhone Duo display while the app's main UI runs on the other — a teleprompter or subject preview on the outer display, for example. The camera capture accessory is available only when the app is full screen on the inner display with an active camera session. ## Size class A coarse description of available layout space, either compact or regular in each dimension. On iPhone Duo the inner display is regular in both dimensions and leaves room for sidebars, while the outer display is compact-width and regular-height. ## Split View multitasking Side-by-side app layout on the iPhone Duo inner display. All apps participate whether or not they opt in, so any app can be given an arbitrary fraction of the display at a moment the user chooses. ## Vertical bar The shared side region on the iPhone Duo inner display in landscape where navigation, toolbar and tab bar controls lay out vertically instead of horizontally, preserving vertical space for content. Apps built against the iOS 27.1 SDK get it with standard containers. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # iPhone Duo developer FAQ > Answers to common iPhone Duo development questions. Source: https://iphoneduosupport.com/faq/ --- ## Will my existing iOS app break on iPhone Duo? No. Apps built without the iOS 27 SDK run on iPhone Duo at a familiar size and aspect ratio. Your app will launch and function. What it will not do is use the display. Apple defined three tiers: without the iOS 27 SDK you get the familiar size; with the iOS 27 SDK your app extends left of the status bar area; only with the iOS 27.1 SDK does it reach the screen edge with vertically laid out bar buttons. So this is a competitive problem rather than a functional one — your app will look dated beside one that fills the 7.6-inch display. ## What are the iPhone Duo screen dimensions in points? Apple publishes pixel dimensions. The inner folding display is 7.6 inches at 1878 × 2670 pixels and 430 ppi. The outer cover display is 5.4 inches at 1398 × 2034 pixels and 460 ppi. At a @3x scale factor that works out to **626 × 890 points** for the inner display and **466 × 678 points** for the outer. Note that the point figures are derived by dividing the published pixel dimensions by three, not published by Apple directly. The inner display's aspect ratio is roughly 1.42, against about 2.17 for iPhone 18 Pro — a substantially squarer screen, which is why fixed-aspect content letterboxes. ## What is the minimum work to make my app look right on iPhone Duo? Four changes account for most of the visible improvement, and none of them require the new APIs: 1. Remove hard-coded screen widths and fixed frame sizes. 2. Stop relying on supported interface orientations — the inner display ignores them. Use size classes instead. 3. Handle safe area insets as asymmetric; never double one side to account for the other. 4. Remove layout branches gated on user interface idiom, which reports phone on a regular-width display. Rebuild against the iOS 27.1 SDK, then work through those. Adopting ArrangementView and reserved regions is worthwhile afterwards, but it is upside rather than the baseline. ## Do React Native and Flutter support iPhone Duo? Neither vendor has shipped iPhone Duo support or published guidance, as of 9 September 2026. Both will still work. React Native's flexbox layout and Flutter's constraint-based layout both adapt when the native view is resized, so an app built without fixed pixel values reflows correctly. What neither can reach today is the fold-aware API surface — reserved regions, arrangements, hinge angle, scene accessories and the vertical bar APIs have no JavaScript or Dart bindings. Getting at them requires a native module or platform channel. Flutter is closest to ready in principle, because MediaQuery.displayFeatures already models hinges and cutouts for Android foldables. Whether the iOS embedder populates it for iPhone Duo is unconfirmed — assume it is empty and verify on a real build. ## Which version of Xcode do I need for iPhone Duo? Xcode 27.1 or later. It includes the iPhone Duo simulator, accessible through Device Hub with on-screen controls to open, close, rotate and fold the device, and the SDK that lets your app reach the screen edge. Xcode 27.1 also extends the app modernization skill — previously "Modernize your UIKit app" — to cover SwiftUI and iPhone Duo under the name App Resizability. Note that on 9 September 2026 Apple listed Xcode 27.1 as beta and "coming later this month", alongside the written documentation and the Human Interface Guidelines page. Until those ship, the six Tech Talk videos are the authoritative source. ## Do I need to keep content away from the fold? Yes, when the device is partially folded. The hinge divides the inner display into separate usable regions, and content across that division is physically bent away from the viewer. The API for this is ReservedRegion in SwiftUI and UIViewReservedRegion in UIKit, querying `kind: .division`. The important behaviour is that a division region is active only while the device is folded and has zero width when flat, so your layout must handle regions appearing and disappearing rather than simply moving. For most main-and-secondary layouts you do not need to query regions directly. ArrangementView already takes active division regions as an input and places your views accordingly. ## How long does iPhone Duo support take to implement? It depends almost entirely on how much your layout code assumes a fixed screen size. An app already built with adaptive layout and an iPad target is often a few days of audit and refinement — the inner display is regular-width in both dimensions, which is the environment an iPad layout already targets. An iPhone-only app with hard-coded dimensions, orientation locks and custom navigation containers is a larger piece of work, because the fixes touch layout code throughout rather than in one place. Games and apps with custom-drawn full-bleed surfaces sit at the harder end, since resolution changes mid-session and the fold has to be handled explicitly. ## Does iPhone Duo use Face ID or Touch ID? We have seen third-party reports that iPhone Duo uses Touch ID rather than Face ID, which would mean `LAContext.biometryType` returns a different value than your app may expect, and any UI hard-coding a Face ID icon or the phrase "Face ID" would be wrong. We have not been able to confirm this from Apple's own developer material, so treat it as unverified and check `biometryType` at runtime rather than assuming either one. That is good practice regardless — it is the reason the API exists. --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc. ============================================================================== # iPhone Duo display reference > Screen dimensions, aspect ratios and size classes for iPhone Duo. Source: https://iphoneduosupport.com/specs/ --- ## Displays | Display | Size | Pixels | Points @3x | Aspect | PPI | | --- | --- | --- | --- | --- | --- | | Inner (folding) display | 7.6" | 1878 x 2670 | 626 x 890 | 1.42 | 430 | | Outer (cover) display | 5.4" | 1398 x 2034 | 466 x 678 | 1.45 | 460 | | iPhone 18 Pro (for comparison) | - | 1206 x 2622 | 402 x 874 | 2.17 | - | Pixel dimensions, sizes and PPI are published by Apple. Point dimensions are derived by dividing pixels by a @3x scale factor and are not published directly by Apple. ## Size classes | Display | Horizontal | Vertical | Notes | | --- | --- | --- | --- | | Inner | Regular | Regular | Leaves room for sidebars. Does NOT honor supported interface orientations. | | Outer | Compact | Regular | Familiar iPhone environment. | ## Three SDK compatibility tiers 1. Not built with the iOS 27 SDK - app runs at a familiar size and aspect ratio. 2. iOS 27 SDK - app extends left of the status bar area on the inner display. 3. iOS 27.1 SDK - app extends to the screen edge; standard navigation and toolbar buttons lay out vertically under the status bar. Source: https://www.apple.com/iphone-duo/specs/ and https://developer.apple.com/videos/play/tech-talks/111461/ --- Published by iPhone Duo Support (https://iphoneduosupport.com). Not affiliated with Apple Inc.