RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/App Dev
App Dev/2026-05-27Intermediate

Supporting iPhone Air and 17 Pro Max New Resolutions Across Six Apps in Parallel

How I added iPhone Air (420×912), 17 Pro (402×874), and 17 Pro Max (440×956) support across six apps in parallel — 29 ternary branches, a 6-app diff script, and a phased rollout that landed at zero resolution-related crashes in 14 days.

ios12iphone-airiphone-17screen-resolutionapp-dev2

Premium Article

Apple shipped three new iPhone resolutions in a single fall: iPhone Air at 420×912, 17 Pro at 402×874, and 17 Pro Max at 440×956. As an indie developer who has been working in Objective-C and Swift on these apps since 2014, this was the most resolution-heavy year I can remember. My catalog — Beautiful HD Wallpapers, Ukiyo-e Wallpapers, Relaxing Healing, Law of Attraction, and two others — all share a common DefineManager.h shape that needed to be updated in parallel.

The legacy ternary-chain macros I'd built up over the years grew by 29 branches in this update, repeated across six apps. The order of those branches is the whole game: get one of them wrong and another device's layout shifts. Here's how I worked through it with Claude on Xcode and what I'd do differently next time.

It started with a single pixel under the safe area

The first sign that something was off came from Xcode 17's new simulators. Beautiful HD Wallpapers, with its AdMob banner pinned above the safe area, was leaving an 8-point sliver of background visible on the 17 Pro Max simulator. Not a crash, not a layout failure — just a thin band of incorrect color where my old offset assumed bounds.size.height == 932.0f.

iPhone Air, at 6.6 inches with Dynamic Island, demands respecting safeAreaInsets rather than reading UIScreen.main.bounds.size directly. Most of my code already did this. The problem was the few legacy macros that didn't.

// The old check that assumed iPhone 16 Pro Max was the tallest device
#define IS_IPHONE_PRO_MAX \
  ([UIScreen mainScreen].bounds.size.height == 932.0f)
 
// 17 Pro Max ships at 956pt vertically, so the predicate flipped

The first internal build I pushed to TestFlight showed the same 8pt gap to every 17 Pro Max user. When you don't own the device — and as an indie developer I usually don't — your safety net is whatever TestFlight + phased rollout can catch in the first 24 hours.

What 29 ternary branches actually look like

The old macros were uncomplicated.

#define IS_IPHONE_AIR \
  ([UIScreen mainScreen].bounds.size.width == 420.0f && \
   [UIScreen mainScreen].bounds.size.height == 912.0f)
 
#define IS_IPHONE_17_PRO \
  ([UIScreen mainScreen].bounds.size.width == 402.0f && \
   [UIScreen mainScreen].bounds.size.height == 874.0f)
 
#define IS_IPHONE_17_PRO_MAX \
  ([UIScreen mainScreen].bounds.size.width == 440.0f && \
   [UIScreen mainScreen].bounds.size.height == 956.0f)

The trouble lived in the macros that returned layout values. Take the navigation bar offset:

#define NAV_BAR_OFFSET \
  (IS_IPHONE_AIR ? 18.0f : \
   IS_IPHONE_17_PRO_MAX ? 22.0f : \
   IS_IPHONE_17_PRO ? 18.0f : \
   IS_IPHONE_16_PRO_MAX ? 20.0f : \
   IS_IPHONE_16_PRO ? 18.0f : 16.0f)

I had 29 of these chains. Inserting three new branches into each, in the right order, while leaving the existing branches untouched, was the work. Air and 17 Pro happen to share an 18pt offset right now — I deliberately wrote them as separate branches anyway. The DRY savings would be one line; the future cost of merging them and then having to split them again would be much higher.

Twelve years of indie iOS work has taught me that "DRY today" and "easy to change tomorrow" are not the same thing. Six months from now I will have forgotten everything I'm not seeing on screen, so verbose code is a letter to my future self.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Reproduce the checklist that took six apps from initial iPhone Air / 17 Pro / 17 Pro Max support to zero resolution-related crashes in 14 days, including 1%→10%→50%→100% phased rollout gates
Port the table-driven refactor I'm using to retire ternary-chain device detection in DefineManager.h before next year's resolution wave
Lift the Crashlytics device.modelIdentifier filter I rely on for monitoring 50M+ downloads across six wallpaper and wellness apps in one session
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-07-16
Placing Native Ads in a Masonry Wallpaper Grid: Designing the Lifetime of an Ad Cell
One native ad in a masonry gallery pushed memory from 180 MB to 420 MB over twenty minutes of scrolling. Here is why cell recycling and ad object lifetime never line up, the pool-based implementation that fixed it, and how I picked the insertion interval from measured numbers.
App Dev2026-07-14
Long-Press Context Menus for a Gallery Item in a Rork Expo App
Long-pressing a wallpaper card does nothing, yet iOS users expect a preview and a menu. From why Pressable alone falls short, to a native context menu with zeego, resolving the scroll-vs-long-press conflict, wiring up save and share, and a custom overlay fallback for Android — all with working code.
App Dev2026-07-09
You Only Need to Capture the 6.9-inch iPhone for App Store Screenshots
App Store Connect only requires two screenshot sizes: the 6.9-inch iPhone and the 13-inch iPad. Building on Apple auto-downscaling for smaller devices, here is how I use fastlane snapshot and frameit to cut the screenshot count for a multi-language app.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →