The Rental Pilot field app is on the App Store and on Android phones in the yard. This is
how a change gets from my desk to a driver’s phone: looked at on a simulated iPhone first, out
to testers through TestFlight in about ten minutes, then to everyone in stages. None of it ships
because a build went green, and like everything I build, it’s designed mobile first.
iOSAndroid
Changecommitted and pushed
Simulatorrendered, screenshotted, read
TestFlightone command, ~10 minutes
App Reviewsubmitted through the API
Phased releasea slice of users first
Everyoneolder builds asked to update
Every change, on a simulated iPhone first
Xcode · iOS Simulator · simctl
A type-check passing or a build going green says the code compiles. It doesn’t say the
screen is right. So every change to the app is built and opened in the iOS Simulator, on a current
Pro-size iPhone, and a screenshot of the actual screen is read before anything moves on. Release
builds get the same treatment: the exact build configuration that goes to Apple runs on the
simulator first.
The simulator is driven from the command line with xcrun simctl: boot a device,
install the build, open a deep link, take the screenshot. Because it’s scripted, an agent can
do the looking and report what’s on screen, and it’s the same check every time.
One script takes a clean checkout to testers’ phones: archive, sign, upload, wait for
Apple to process it, and hand it to the TestFlight testers. It takes about ten minutes, and it
refuses to run from anything but a clean, up-to-date copy of the code, so what testers get is
exactly what’s in the repository.
That makes small builds cheap. On a busy day the field app goes out to testers six or eight
times, each one a fix someone asked for that morning, instead of a big release every few weeks.
Submitting for review, writing the “What’s New” notes, and swapping a newer build
in for one still waiting in the queue all run through the App Store Connect API instead of
clicking through the website. When a better build is ready before Apple has looked at the last
one, the waiting submission is pulled and the new build goes in its place within minutes.
Approved versions release in phases, a small share of users first and growing over seven days,
so a problem reaches a few phones instead of all of them. Once a release has proven itself it can
be pushed to everyone early.
App Store Connect API
phased release
Android, proven on the emulator
Expo EAS · Android Emulator · adb
Android builds come out of Expo’s cloud build service as an installable app, shared with
the people who need it by a single link. Before a link goes out, the new build is installed over
the previous one on the Android emulator. That upgrade only succeeds if the signing key matches,
so it’s the cheapest proof that a tester’s phone will update in place instead of
refusing.
iPhone and Android share one build number, so the same code shows the same version on both, and
a bug report always says exactly which build it came from.
The app asks the server, on launch, what the oldest build it still supports is. A phone below
that line gets a clear “update the app” screen that sends it to the right store, instead
of an old build quietly working against a newer server. That’s what makes shipping small and
often safe: the field never drifts far behind.