KibiPay
HomeBlog › Mobile

From Prototype to TestFlight: Shipping an Expo Wallet to iOS

8 min read Mobile
MobileDevOps
From Prototype to TestFlight: Shipping an Expo Wallet to iOS

A mobile wallet running in a simulator on your laptop is a demo. A wallet on a real iPhone, installed through TestFlight, is a product people can actually try. Getting from one to the other used to mean Xcode, a Mac, provisioning-profile spelunking and code-signing misery. KibiPay's Expo wallet takes a much shorter path — and, notably, doesn't require a Mac at all.

The fastest loop: Expo Go

Before any of the store machinery, there's an instant inner loop. Running npx expo start and opening the project in Expo Go on a phone puts the real app in your hand in seconds — no build, no Apple account, no signing. That's where day-to-day development happens. TestFlight is for when you want a standalone, installable build that behaves exactly like the shipped app, distributed to testers who don't have your dev environment.

EAS Build: a real iOS binary in the cloud

The heavy lifting is done by EAS Build, Expo's cloud build service, configured through an eas.json with three profiles: a development profile (a dev client, for internal use and simulators), a preview profile (internal distribution to real devices on a preview channel), and a production profile that builds the store-bound binary. The production profile auto-increments the build number and runs on a suitable cloud build machine.

The magic is what EAS handles for you. Running the production iOS build kicks off a cloud build that automatically creates the iOS distribution certificate and provisioning profile and registers the App ID — the exact steps that traditionally required Xcode and a Mac. Because the build version source is set to remote, EAS owns and increments the build number, so you never hand-bump a number or collide with a previous upload. The output is a signed .ipa, produced without a single line of native code touched by hand.

The config that keeps TestFlight happy

A few details in the app config exist specifically to make the store submission smooth. The iOS infoPlist declares the permission-usage strings Apple requires and will reject you for omitting: an NSCameraUsageDescription (the wallet scans QR codes) and an NSFaceIDUsageDescription (it gates payments with Face ID). It also sets ITSAppUsesNonExemptEncryption to false, which truthfully declares the app uses no non-exempt cryptography and skips the export-compliance questionnaire that otherwise stalls every single upload. Getting these right up front is the difference between a submission that sails through and one that bounces back a day later.

Submitting to TestFlight

With a build in hand, the path to testers is short: create an app record in App Store Connect, fill in the submission credentials (the Apple id, the App Store Connect app id, the team id) in the production submit profile, and run the submit command. EAS Submit uploads the binary straight to App Store Connect, where it becomes available in TestFlight for internal and external testers. Android is symmetric — the same EAS pipeline builds and submits an Android binary — so a single toolchain covers both stores.

Why this matters for a prototype

The point of making TestFlight easy is that real feedback needs the real thing. A wallet is about feel — how fast sign-in is, whether the QR scan just works, whether Face ID confirmation feels reassuring rather than annoying. None of that is testable in a simulator on your desk. By collapsing "ship it to an iPhone" from a multi-day Xcode ordeal into a couple of cloud commands, the prototype can get into testers' pockets while it's still a prototype — which is exactly when the feedback is worth the most. A runbook in the repo captures the full sequence so any developer can take the wallet from a fresh checkout to a TestFlight build without institutional knowledge.

Three profiles for three audiences

The build configuration mirrors how software actually reaches people. The development profile produces a dev client for engineers and simulators — the tightest loop short of Expo Go. The preview profile builds an internally-distributed binary on its own release channel, the thing you hand to a colleague or a stakeholder to try on their own device without going near the App Store. The production profile builds the store-bound binary, auto-incrementing its build number from the server so uploads never collide. Separating these means "let me try it on my phone," "let a few insiders test it," and "submit to TestFlight" are distinct, repeatable commands rather than one fragile process reconfigured by hand each time. Channels tie a build to the stream of over-the-air updates it should receive, so a preview build keeps getting preview updates and a production build gets production ones. The whole arrangement is captured in a runbook checked into the repository, which is the real deliverable: it means shipping the wallet to iOS doesn't depend on one person remembering the incantations, and a fresh developer can go from checkout to a build in testers' hands by following written steps.

See it in motion

KibiPay connects UK Faster Payments, Bacs, CHAPS, Mojaloop mobile money, a mock ACH rail and Solana behind one API, with a cross-rail alias directory, ISO 20022 messaging and real-time fraud & AML screening.

Open the live console Directory demo