How we ship an app to the App Store and Google Play
People assume the hard part of an app is the app. Then they finish one, press what they think is the publish button, and discover there isn’t one. Getting to live on the App Store and Google Play is its own project, with its own rules, its own review queues, and its own ways to fail at the last step. We run this loop for our own products, Kerbnow and RHUL Mobile, so here is what it actually takes.
The build is not the thing you tested
The app you ran on your desk all week is a debug build. The stores want a signed, optimised release build, and that is a different animal. Our apps are Expo and React Native, so we produce store builds with EAS Build: one command puts out a signed .ipa for Apple and an .aab for Google, with the certificates and provisioning handled in the cloud rather than on somebody’s Mac.
The traps here are boring and expensive. A bumped version and build number, because the stores reject a number they have already seen. The right bundle identifier and signing on iOS. On Android, the upload key has to match what Google expects, or the whole thing bounces before a human ever looks at it. We have also been caught by client-side environment keys not making it into the release bundle, which passes every test on your machine and then fails silently in the wild, so we now check the actual build artefact before it goes anywhere near a store.
Listings and metadata are half the job
A finished build sitting in App Store Connect or the Play Console still shows nothing to a shopper. You have to build the listing: name, subtitle, description, keywords, category, age rating, a privacy questionnaire, support and marketing URLs, and screenshots for a range of device sizes. Apple and Google each want their own set at their own dimensions, and a missing size holds up the whole submission.
This is also where app store optimisation lives, which is the store’s version of SEO. The title and the keyword field on Apple carry real weight, so we write them for what people actually type, not for what we wish they called the thing. Kerbnow is a UK parking sign decoder, so it needs to read as that in the first line, not as something clever. Good screenshots do most of the persuading, because almost nobody reads the description. We treat the first two screenshots as the pitch and caption them plainly.
Review is a real gate, and it bites late
Both stores put a build through review before it goes live. Apple’s is stricter and slower, usually running from a day to a few days, and it is done partly by a person. Google leans more automated and tends to be quicker, though it is less predictable than it used to be. Either way, you get review builds in front of testers first: TestFlight on Apple, internal testing on Google Play. That is where you catch the embarrassing stuff before a reviewer does.
The rejections that catch people out are rarely about the idea. The common ones we plan around:
- Privacy details. Apple wants a privacy manifest declaring the data you collect and the reason you touch certain APIs, plus an accurate privacy questionnaire. Get it wrong and you are rejected, or worse, accepted then bounced later.
- In-app purchase configuration. If you sell anything, the products have to exist and be approved on the store side, not just in your code. We use RevenueCat to run purchases and subscriptions across both platforms, but RevenueCat still needs the matching products set up in App Store Connect and the Play Console, or the paywall loads empty and the reviewer marks it broken.
- Metadata mismatches. Screenshots that show features the build does not have, a description that promises more than ships, a demo login that does not work. Reviewers check these, and they are an easy avoidable no.
None of these are hard. They are just easy to forget when you are focused on the code, and each one costs you a full review cycle.
Uploading, and when the upload fights back
With the build made and the listing filled in, you submit. We use EAS Submit to push the artefact to both stores, which handles the upload and the paperwork in one go. When it behaves, it is a single command. When it does not, an eas submit can hang and quietly send nothing, so we keep a fallback: fastlane, or xcrun altool straight to Apple with the API key. Knowing the manual route matters, because a stuck upload on release day is not the moment to learn it.
Phased release, then you own it
We do not flip an app to everyone at once. Both stores support a phased or staged rollout, where the new version goes to a small share of users first and widens over days. If something is wrong, you find out at a fraction of the audience and can halt it, rather than shipping a bad build to the whole base in one go.
And then the part people skip in their heads: going live is the start, not the finish. Now you are watching crash reports, answering store reviews, keeping subscriptions and receipts working, and turning up again for the next OS version that quietly breaks something. We build the app, we get it through both stores, and then we keep it running, which is the actual job.
None of this is glamorous. It is a checklist you respect, and it is the difference between an app that exists and one that ships.