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.
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:
@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.
// 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:
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.
// 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:
// 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.
MediaQueryhandles it; cached values do not. - Check
AppLifecycleStatehandling. In Split View your app can be visible but not resumed. Anything paused oninactive— video, animation controllers, timers — will look frozen to a user who can still see it.
A pragmatic migration
- Log
displayFeatureson a real iPhone Duo build and find out where you stand - Replace cached
MediaQueryreads withsizeOfinbuild - Audit
paddingOfconsumers for symmetric assumptions - Replace platform-based layout checks with width checks
- Remove orientation preferences used as a layout strategy
- Test the Split View divider and the lifecycle-pause path
- 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.