Skip to content

The iPhone Duo Framework Scorecard

iPhone Duo framework support compared

Six iOS frameworks, each scored against the common patterns its own code can express: what already works on iPhone Duo, what breaks, what merely looks dated, and what cannot be reached without native code. Maintained by Ingenious Techlab and updated as vendors ship support.

Apple-side facts are sourced from Apple’s iPhone Duo developer material. The verdicts on third-party frameworks are our engineering analysis, because no cross-platform vendor has published iPhone Duo guidance. Each framework’s own guide shows the code behind every row.

FrameworkVendor supportWorksBreaksLooks datedUnverifiedNeeds native
SwiftUIApple ships the APIs76100
UIKitApple ships the APIs76000
React NativeNothing shipped45221
FlutterPartial / unconfirmed45221
UnityNothing shipped35101
Capacitor & web viewsNothing shipped35101

Counts are of common patterns we checked per framework, not a severity score: a single “breaks” row can be more work than four others combined. The totals differ between frameworks because the patterns differ — a Dart widget has no UIKit equivalent to check.

What the verdicts mean

SwiftUI

Apple ships the APIs

Needs work

  • .frame(width: 390) Sized for a 402 pt iPhone, on a 626 pt display.
  • Layout driven by orientation The inner display ignores supported orientations.
  • bounds.width - insets.left * 2 Insets are asymmetric; content drifts off-centre.
  • userInterfaceIdiom == .pad gates iPhone Duo reports `.phone` with a regular-width display.
  • UIScreen.main Two displays at different densities; read the window scene.
  • Layout driven by onHingeChange Hinge angle is for interactions and effects, not layout.
Full SwiftUI guide

UIKit

Apple ships the APIs

Needs work

  • Custom UIToolbar content Not placed in the side column.
  • UIScreen.main.scale and .bounds Displays run at 430 and 460 ppi; use traits and the window scene.
  • userInterfaceIdiom layout gates Phone idiom, regular-width display: iPad layouts never appear.
  • bounds.width - insets.left * 2 Left and right insets differ.
  • UIRequiresFullScreen Honoured, but the app scales instead of being exempt.
  • Pausing on sceneWillResignActive A visible app in Split View can resign active and look frozen.
Full UIKit guide

React Native

Nothing shipped

Needs work

  • Dimensions.get('window') at module scope Captured once at launch; wrong after the first fold.
  • A portrait orientation lock The inner display ignores supported orientations.
  • Math.max(insets.left, insets.right) Insets are asymmetric; one side is over-padded.
  • Platform.isPad False on iPhone Duo, so the tablet layout never appears.
  • Pausing on AppState inactive In Split View a visible app can be inactive — it looks frozen.
  • Hinge, ArrangementView, vertical bars No JavaScript bindings; needs a native module.
Full React Native guide

Flutter

Partial / unconfirmed

Needs work

  • Screen size cached in State Stale after the first fold, rotation or Split View resize.
  • SystemChrome.setPreferredOrientations The inner display ignores supported orientations.
  • OrientationBuilder as a layout signal Reports shape, not room. Branch on width.
  • EdgeInsets.symmetric(horizontal: …) Asserts a symmetry the insets no longer have.
  • Pausing on AppLifecycleState.inactive In Split View a visible app can be inactive.
  • ArrangementView, vertical bars No Dart API; needs a platform channel.
Full Flutter guide

Unity

Nothing shipped

Needs work

  • Screen.width and Screen.height cached in Start() Resolution changes mid-play on fold, unfold and Split View.
  • One horizontal margin from Screen.safeArea Left and right insets differ.
  • Stopping time in OnApplicationPause Folding can leave a visibly frozen game on screen.
  • Input regions in cached pixels Joystick bounds and tap zones go stale after a resize.
  • Critical HUD in the centre of the inner display Sits on the fold when the device is partly open.
  • The hinge (reservedRegions(kind:)) No Unity binding; needs a native plugin.
Full Unity guide

Capacitor & web views

Nothing shipped

Needs work

  • Missing viewport-fit=cover `env(safe-area-inset-*)` resolves to zero.
  • padding: 0 env(safe-area-inset-left) Applies one side’s inset to both.
  • User-agent layout branching Serves the phone layout to a 626 pt regular-width display.
  • 100vh full-height layouts Misbehaves as the viewport changes; use `100dvh`.
  • A cached window.innerWidth Stale after a fold or a Split View resize; use `ResizeObserver`.
  • Hinge, reserved regions, scene accessories No web API; needs a native plugin.
Full Capacitor & web views guide

The short version

SwiftUI and UIKit have first-party adaptive APIs: arrangements, reserved regions and vertical bar behaviours are all available to them, and most of the work is configuration rather than rewriting. Every cross-platform framework is, so far, on its own. None of them exposes the fold, and each needs a native module or platform channel to reach it.

That does not make them unusable. Flutter’s layout system is resolution-independent and React Native’s flexbox reflows on its own, so most screens adapt without fold-specific code. What breaks in both is the same short list: a size cached at launch, an orientation lock the inner display ignores, safe-area maths that assumes symmetry, and pausing on the wrong lifecycle event.

The inner display is 626 × 890 points and the outer 466 × 678 — see the display reference and the full compatibility checklist.