Produce a reproducible signing, versioning, and store-declaration pipeline so an iOS or Android build passes App Store Connect / Play Console submission. Use when building or uploading a distribution .ipa/.aab, fixing signing/provisioning-profile or entitlement errors, bumping CFBundleVersion/versionCode, filling App Privacy / Data safety forms or PrivacyInfo.xcprivacy, wiring Fastlane lanes, or diagnosing a store rejection. Do NOT use for general (non-mobile) release steps like changelogs, tagging, or backend deploys - use prepare-release instead; do NOT use for store listing titles, descriptions, or keywords - use app-store-copy instead.
Click to play with sound.
---
name: App Store Release Prep
description: Produce a reproducible signing, versioning, and store-declaration pipeline so an iOS or Android build passes App Store Connect / Play Console submission. Use when building or uploading a distribution .ipa/.aab, fixing signing/provisioning-profile or entitlement errors, bumping CFBundleVersion/versionCode, filling App Privacy / Data safety forms or PrivacyInfo.xcprivacy, wiring Fastlane lanes, or diagnosing a store rejection. Do NOT use for general (non-mobile) release steps like changelogs, tagging, or backend deploys - use prepare-release instead; do NOT use for store listing titles, descriptions, or keywords - use app-store-copy instead.
---
# App Store Release Prep
Turn a mobile release into a reproducible pipeline - correct signing, monotonic build numbers, complete privacy declarations - so submission to App Store Connect or Play Console succeeds on the first upload.
## Workflow
1. **Establish identity and signing first; it is the most common blocker.**
- iOS: a distribution build needs a distribution certificate plus a provisioning profile whose app id, capabilities, and entitlements all match the build. Store and sync these with Fastlane `match` in a shared encrypted repo so every machine and CI sign identically. Verify the profile matches the bundle id and enabled capabilities before building. Note that distribution certificates expire after one year - track the expiry so it never surprises a release week.
- Android: sign with an upload key and enroll in Play App Signing so Google holds the app signing key. A lost upload key is recoverable via the Play Console; protect the app signing key regardless.
2. **Set both version numbers correctly.**
- Marketing version (`CFBundleShortVersionString` / `versionName`) is human-facing and may repeat across uploads.
- Build number (`CFBundleVersion` / `versionCode`) must strictly increase on every upload - including re-uploads of a rejected build. Automate it with `increment_build_number` or derive it from the CI build count so you never collide with an existing upload. Android's `versionCode` has a hard ceiling of 2,100,000,000 - avoid date-encoded schemes that burn through the range.
3. **Build the signed artifact through a defined lane.**
- Define Fastlane lanes: `build`, `beta`, `release`. Use `gym`/`build_app` to produce the signed `.ipa`/`.aab`, `pilot`/`upload_to_testflight` and `supply`/`upload_to_play_store` to push it, `deliver` for metadata/screenshots.
- Run the lane on a tagged commit in CI so releases are reproducible, not laptop-dependent.
- Remember TestFlight builds expire 90 days after upload - a beta program needs a re-upload cadence well inside that window.
4. **Complete gating declarations - they cause rejection, not warnings.**
- iOS: fill the App Privacy "nutrition labels" and ship `PrivacyInfo.xcprivacy` declaring data use and required-reason API usage.