Build, Release & App Store Deployment
Build, Release & App Store Deployment
Shipping a Flutter app to the Google Play Store or the Apple App Store is the final milestone of any production project. This lesson walks you through the complete release pipeline: configuring code signing for Android and iOS, setting version metadata, producing optimised release builds, and navigating the submission workflows for both stores.
Versioning Your App
Flutter controls the version shown to users and the internal build counter through a single line in pubspec.yaml:
pubspec.yaml — version field
# version: <user-visible version>+<build number>
version: 1.2.0+5
# Maps to:
# Android: versionName="1.2.0" versionCode=5
# iOS: CFBundleShortVersionString=1.2.0 CFBundleVersion=5
The part before the + is the marketing version (shown in the stores). The integer after + is the build number — it must be incremented with every upload to either store. You can override these values from the CLI at build time:
Overriding version at build time
flutter build apk \
--build-name=1.2.0 \
--build-number=5
Android: Signing with a Keystore
Every Android APK or App Bundle must be signed with a private key. You create a keystore once and reuse it for the lifetime of your app — losing the keystore means you can never update your app on the Play Store.
1 — Generate a keystore (run once)
keytool -genkey -v \
-keystore ~/keys/my-release-key.jks \
-keyalg RSA -keysize 2048 \
-validity 10000 \
-alias my-key-alias
Store the generated .jks file and its passwords somewhere safe (a password manager or encrypted backup). Next, create android/key.properties — add this file to .gitignore immediately:
android/key.properties
storePassword=yourStorePassword
keyPassword=yourKeyPassword
keyAlias=my-key-alias
storeFile=/Users/you/keys/my-release-key.jks
Finally, update android/app/build.gradle to load those properties and apply them to the release signing config:
android/app/build.gradle — signing config
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
}
}
}
key.properties or the .jks keystore to your git repository. Anyone with those files can publish updates to your app pretending to be you. Add both to .gitignore and store them in a secure vault.Building a Signed Android Release
Google Play requires an App Bundle (.aab) rather than a plain APK for new apps. An App Bundle lets the Play Store deliver optimised APKs per device architecture and screen density, reducing download sizes.
Build a signed App Bundle
# Preferred for Play Store submission
flutter build appbundle --release
# Output: build/app/outputs/bundle/release/app-release.aab
# For direct APK distribution (sideloading / testing)
flutter build apk --release --split-per-abi
# Output: build/app/outputs/flutter-apk/
# app-armeabi-v7a-release.apk
# app-arm64-v8a-release.apk
# app-x86_64-release.apk
iOS: Certificates and Provisioning Profiles
iOS code signing requires an Apple Developer account. The process involves three artefacts:
- Signing Certificate — proves your identity as a developer (Distribution certificate for App Store).
- App ID (Bundle Identifier) — a unique reverse-domain string registered in the Apple Developer portal (e.g.
com.example.myapp). - Provisioning Profile — links your certificate, App ID, and (for ad hoc) device UDIDs. Use an App Store Distribution profile for submissions.
In Xcode, open ios/Runner.xcworkspace, select the Runner target, and under Signing & Capabilities choose your team. With Automatically manage signing enabled, Xcode downloads and refreshes certificates and profiles for you.
match action to sync certificates and profiles from a private git repo or Google Cloud Storage bucket. This keeps all machines in sync without manual Xcode interaction.Building a Signed iOS Release
Build an iOS archive for App Store submission
# Build with Xcode signing
flutter build ipa --release
# The .ipa is placed at:
# build/ios/ipa/<AppName>.ipa
# If you need to specify the export method explicitly:
flutter build ipa \
--export-options-plist=ios/ExportOptions.plist
Upload the resulting .ipa to App Store Connect using Xcode Organizer (Product > Archive > Distribute App) or the xcrun altool / xcrun notarytool CLI tools. Alternatively, use Transporter (a free Apple app) for a drag-and-drop upload experience.
Google Play Store Submission Checklist
- Create a new app in the Google Play Console and fill in the store listing (screenshots, description, content rating).
- Upload your
app-release.aabto the Internal Testing track first to validate it, then promote to Production. - Set a rollout percentage (e.g. 10 %) for staged releases so you can catch crashes before reaching all users.
- Ensure
versionCodeis strictly greater than the previous upload or the upload will be rejected.
Apple App Store Submission Checklist
- In App Store Connect, create a new app version and fill in the What's New text, screenshots (multiple device sizes), and App Review information.
- Upload the
.ipaand wait for processing (usually 5–30 minutes). - Select the build in the version page and submit for review. Average review time is 24–48 hours.
- Ensure the
CFBundleVersion(build number) is strictly greater than any previously uploaded build — even rejected ones count.