Shipping to Both Stores Without Losing Your Mind

April 3, 2026 (5mo ago)

Building the app is the easy half. Getting it through both Apple’s and Google’s review pipelines, repeatedly, without breaking something each time, is where most of the friction lives. Here’s the routine I’ve settled into.

Version everything from one source

Keep version in pubspec.yaml as the single source of truth and let your CI derive the build number:

version: 1.4.0+42  # marketing version + build number

A mismatched build number is the most common reason an otherwise-fine upload gets rejected. Automating it removes the human error entirely.

Signing, once

  • Android: store the keystore and its passwords in CI secrets, never in the repo. A leaked keystore means you can never update that app again.
  • iOS: use a dedicated CI signing identity and managed provisioning. Fighting Xcode’s automatic signing on a build server is a losing battle.

The review gotchas

  1. Permissions need a reason. Every NSCameraUsageDescription-style string must explain why. Vague text gets flagged.
  2. Sign in with Apple. If you offer any third-party login on iOS, Apple requires their option too.
  3. Account deletion. Both stores now expect an in-app path to delete an account if you can create one.

Make releases boring

The goal is for a release to be a non-event: tag the commit, let CI build and upload to both TestFlight and the Play internal track, smoke-test, promote. Boring releases are reliable releases.