iphone-duo-adaptivity-audit
Skill6 starsChanged 37 days agoMITView on GitHub
Find and fix legacy screen, orientation, idiom and lifecycle code that breaks on iPhone Duo's inner display and in other iOS 27 resizable environments (iPhone Mirroring, iPhone apps on iPad, Split View). Use when a developer asks about UIScreen.main or mainScreen, screen bounds or scale, interfaceOrientation or UIDevice orientation checks, userInterfaceIdiom layout forks, keyWindow or connectedScenes.first, migrating from app lifecycle to UIScene lifecycle (required with the latest SDK), UIRequiresFullScreen, a missing launch screen (ITMS-90870), portrait-only apps, or hard-coded Face ID strings and symbols (iPhone Duo has Touch ID; branch on LAContext.biometryType). Covers SwiftUI and UIKit, ships a read-only scanner, and delegates bulk UIKit rewrites to Xcode's own modernization skill when available. Not for app features that merely touch UIScreen or orientation, such as screen brightness, deliberately locking a game to one orientation, or camera and sensor setup.
1 other project uses a version of this, 1 of them edited.
Adopted by
Most recently taken up by
- Urbanrenewalroridula3044/iPhone-Duo-Agent-Skilledited, first seen Oct 20, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 1
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository5 other files it gives its agents.
- AGENTS.mdAGENTS.md
- iphone-duo-barsSkill
- iphone-duo-displaysSkill
- iphone-duo-layoutSkill
- iphone-duo-readinessSkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 2 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 53
UIScene lifecycle is required: when building with the latest SDKs.
- Very specific: line 58
Remove the key only after the layouts adapt: removal makes the scene resize continuously at once.
- Very specific: line 60
Add UIRequiresFullScreenIgnoredStartingWithVersion only after that too: a value of 27 or earlier also makes the scene resize continuously …
- Very specific: line 95
Ask first whether a .pad gate means "iPad" or "a big screen".
- Very specific: line 98
Check the hardware too: iPhone Duo supports Apple Pencil (USB-C) without hover (references/device-geometry.md), so a hover preview stays …
- Very specific: line 109
If it yields uikit-app-modernization (Xcode 27.0) or App Resizability (27.1), use it for bulk UIKit rewrites: it applies …
- Very specific: line 146
Typecheck what you touched: Run the project's build, or at least xcrun --sdk iphonesimulator swiftc -typecheck on the edited files at the …
- Distinctive: line 157
Orientation replacement is not always width > height: When left versus right matters (cutouts, camera side), ask before replacing.
- Very specific: line 170
Leave UIRequiresFullScreen alone in games that need discrete resizing.
- Very specific: line 172
Never add UIRequiresFullScreenIgnoredStartingWithVersion as a first step.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
iPhone Duo adaptivity audit
The foundation for everything else: an app that decides layout from the screen, the orientation or the idiom is wrong on iPhone Duo before any foldable-specific work begins.
Facts this skill relies on
- The outer display behaves like other iPhones; the inner display is regular width × regular height. (Tech Talk 111461, 2:46)
- The inner display does not honor supported interface orientations; in iOS 27 supported orientations are a preference ignored in resizable environments, and iPhone Mirroring always reports portrait. (111461 2:46; WWDC26 278 6:50)
- Referencing the main screen is ambiguous on a two-display device and deprecated
(the iOS 27 SDK header marks
mainScreendeprecated). (111461 3:57; 278 2:51) Concretely: the iPhone Duo simulator's own profile names the outer display asmain-screen-*, so an app that asks for the main screen gets the smaller of the two whichever display it is actually on. (references/device-geometry.md, measured) - The user interface idiom is not meaningful for layout: an iPhone app stays in the phone idiom while fully resizable. (111461 1:33; 278 6:17) iPhone Duo has no idiom of its own and no API that identifies it (Forums 847775, 847644). An iPhone-only app cannot opt out of resizing on iPad or in iPhone Mirroring either (Forums 847872; 278 1:32).
- A fold is a size-class and trait change, not a scene event. Opening, closing and
folding keep the process and the scene; text input, scroll position and playback
survive (Forums 848042, 847644). Do not save a fold state on the way to the
background or restore one on the way back: reserved regions and hinge data are
current when the scene returns (Forums 848035).
windowScene(_:didUpdateEffectiveGeometry:)is guaranteed when the scene moves to the other display (Forums 848021), but layout-time adaptation is the better route, and folding alone does not call it (Booted,scripts/probes/forum_probe.swiftin the repository). - The SDK alone picks the compatibility tier. No
Info.plistkey brings back the boxed presentation once the app links the iOS 27 SDK (Forums 847856;references/api-availability.md› What each linked SDK gets). - UIScene lifecycle is required when building with the latest SDKs; without it the app no longer launches. (278 2:10)
UIRequiresFullScreenno longer opts an app out of resizing from iOS 27: it gives discrete resizing, and iPhone Duo still resizes the app when it opens or closes and scales it on the inner display, including in Split View — meant for games. Remove the key only after the layouts adapt: removal makes the scene resize continuously at once. AddUIRequiresFullScreenIgnoredStartingWithVersiononly after that too: a value of 27 or earlier also makes the scene resize continuously on iOS 27. (278 5:46; 111461 4:37; TN3192)- App Store Connect requires a launch screen. An upload built with the iOS 27 SDK
needs
UILaunchScreen,UILaunchScreens,UILaunchStoryboardNameorUILaunchStoryboardsin theInfo.plist, or App Store Connect rejects it withITMS-90870. An emptyUILaunchScreendictionary orINFOPLIST_KEY_UILaunchScreen_Generation = YESis enough. (TN3208; TN3192) - iPhone Duo has Touch ID in the side button and no Face ID (Apple tech specs;
references/device-geometry.md). Adaptive apps make no assumptions about device capabilities (111461 2:34): copy, symbols and onboarding that name Face ID are wrong on it.
Workflow
- Scan (read-only):
Rules owned here:python3 scripts/duo_scan.py <root> --format markdown python3 scripts/duo_scan.py <root> --format json # for exact IDsDUO001main screen,DUO002screen bounds,DUO003idiom,DUO004orientation,DUO005app lifecycle,DUO009global window state,DUO012scene delegate without manifest,DUO013Face ID copy,DUO020UIRequiresFullScreen,DUO022no launch screen. Member chains split across lines (connectedScenes….first) are joined before matching; other multi-line expressions, macros and generated code are not seen, so follow up with targeted searches when the inventory suggests more. - Classify each match by reading the code:
- Layout decision (sizes, columns, which view to show) → replace.
- Rendering scale (
scale, pixel alignment, image sizes) → replace with trait. - Physical question no geometry answers (which end holds a cutout, sensor frame alignment before body protocols) → kept if documented; otherwise ask.
- Non-layout behavior keyed off idiom (feature availability, analytics) → kept,
with a comment naming why.
Ask first whether a
.padgate means "iPad" or "a big screen". A feature hidden on iPhone for lack of room stays hidden on the inner display, because iPhone Duo is.phonethere too: that gate is a layout decision. Check the hardware too: iPhone Duo supports Apple Pencil (USB-C) without hover (references/device-geometry.md), so a hover preview stays off. - Capability assumption (Face ID in strings,
faceidsymbols, onboarding) → derive fromLAContext.biometryType.DUO013reportsmediumwhere nothing in the file ever asked, andlownext to an existingbiometryTyperead — confirm those strings sit in the.faceIDbranch and mark them kept.
- Check Xcode's skill. Export into a temporary directory — without
--output-dirthe command writes into the current directory:
If it yieldsout="$(mktemp -d)" && xcrun agent skills export --output-dir "$out" >/dev/null 2>&1; ls "$out"uikit-app-modernization(Xcode 27.0) or App Resizability (27.1), use it for bulk UIKit rewrites: it applies deprecate-and-forward patterns, preserves guards and control flow, and tracks file coverage. Review its diff against the approved items. SwiftUI code and anything it leaves as a TODO come back here. Installed as an agent skill, it also triggers on "get my app ready for iPhone Duo" and applies every task it has; scope it to the approved items first. - Recommend in the format of
references/recommendation-format.md; wait for approval; apply; build; re-scan.
Replacements
Full before/after code for SwiftUI and UIKit: references/legacy-api-remediation.md.
| Legacy | UIKit replacement | SwiftUI replacement |
UIScreen.main.scale | traitCollection.displayScale (auto-tracked in layoutSubviews, draw(_:), updateProperties; else registerForTraitChanges) | @Environment(\.displayScale) |
UIScreen.main (the screen) | view.window?.windowScene?.screen; pass a UIScreen parameter where no view is at hand | Rarely needed — ask what the screen is for |
UIScreen.main.bounds for available space | view.bounds in viewDidLayoutSubviews; scene level: windowScene.effectiveGeometry + windowScene(_:didUpdateEffectiveGeometry:) | GeometryReader, onGeometryChange(for:of:action:), containerRelativeFrame |
userInterfaceIdiom == .pad for layout | traitCollection.horizontalSizeClass / container size | @Environment(\.horizontalSizeClass) |
interfaceOrientation, UIDevice.current.orientation for layout | Size classes or bounds.width > bounds.height | Size classes or geometry aspect |
Scene interfaceOrientation (deprecated in 27 SDK) where orientation is truly needed | windowScene.effectiveGeometry.interfaceOrientation | same, from the view's window scene |
| Orientation to align sensor data | motionManager.deviceMotionBody = view, locationManager.headingBody = view | same, on a hosting view |
UIApplication.shared.keyWindow / windows / connectedScenes.first | view.window, view.window?.windowScene | the view's own context; openWindow/dismissWindow environment actions |
| App lifecycle only | UIApplicationSceneManifest + UIWindowSceneDelegate; move window setup to scene(_:willConnectTo:options:) | @main struct …: App is already scene-based |
"Face ID" in copy, faceid symbols | A switch context.biometryType (.faceID, .touchID, default) after canEvaluatePolicy, feeding titles and UIImage(systemName:) | The same switch in a small model feeding Label / Button(_:systemImage:) |
Applying changes
- Preserve today's behavior on today's devices. A replacement that is correct on iPhone Duo but turns a two-column portrait / four-column landscape grid into three columns on a small iPhone is a regression. State the before/after on at least one existing device.
- Kept means kept. For a documented exception, change only the deprecated call it
uses (for example
scene.interfaceOrientation→effectiveGeometry.interfaceOrientation). Restructuring it — new representables, observers, different data flow — is a separate proposal for the developer to approve, because the documentation exists precisely so that nobody "improves" it unasked. - Typecheck what you touched. Run the project's build, or at least
xcrun --sdk iphonesimulator swiftc -typecheckon the edited files at the deployment target, and re-runduo_scan.py. Report what was and was not verified.
Pitfalls
- A size class is not a device. Regular × regular now includes an iPhone. Code that reads "regular means iPad" must become "regular means room for more columns".
- Don't cache screen-derived values in
initor static storage; closing or opening iPhone Duo moves the scene to another display. Recompute on trait or geometry change. - Orientation replacement is not always width > height. When left versus right matters (cutouts, camera side), ask before replacing.
- Scene lifecycle migration touches app state restoration, URL handling, push
notification routing and background tasks. Plan it as its own item and read
Xcode's
scene-lifecycle-task.mdreference when available, or Apple's Transitioning to the UIKit scene-based life cycle (Forums 848011). - Fold handling in a scene delegate is a finding, not a migration step. State
restoration (
stateRestorationActivity(for:)) is for a real scene disconnection, not for a fold (Forums 847644). traitCollectionDidChange(_:)is deprecated since iOS 17. It still behaves the same on iPhone Duo (Forums 848021), so move off it as code is touched rather than as a blocker:registerForTraitChanges(_:handler:)or automatic trait tracking (278 2:51). The scan inventory counts it.- Leave
UIRequiresFullScreenalone in games that need discrete resizing. For other apps, recommend adapting first and removing the key after that. Never addUIRequiresFullScreenIgnoredStartingWithVersionas a first step. - Localization catalogs hide biometric copy. The scanner reads Swift and
Objective-C only; grep
.stringsand.xcstringsfor "Face ID" and build those sentences from the biometry name instead. KeepNSFaceIDUsageDescription: Face ID devices still need it.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

