A step-by-step guide to deploying your first Flutter app to both App Store and Play Store, including CI/CD setup.
Deploying a Flutter app to both platforms simultaneously is one of Flutter's biggest value propositions. But the process has enough platform-specific quirks to trip up even experienced developers. Here's the complete guide.
Prerequisites
Before you start, make sure you have:
Apple Developer Account ($99/year)Google Play Developer Account ($25 one-time)Xcode installed (for iOS)Android Studio installed (for Android)Flutter doctor showing all green checksiOS Setup
1. Configure Signing
Open your project in Xcode:
open ios/Runner.xcworkspace
In Xcode:
Select Runner → Signing & CapabilitiesSelect your TeamChange Bundle Identifier to something unique2. Configure Info.plist
Add required permissions:
<key>NSCameraUsageDescription</key>
<string>This app needs camera access for photos</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access</string>
3. Build for iOS
flutter build ios --release
Then archive and upload through Xcode or use:
flutter build ipa --release
Android Setup
1. Configure build.gradle
android {
defaultConfig {
applicationId "com.yourname.yourapp"
minSdkVersion 21
targetSdkVersion 34
versionCode 1
versionName "1.0.0"
}
}
2. Generate Keystore
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload
3. Build for Android
flutter build appbundle --release
The AAB file goes to Google Play, APK for direct distribution.
CI/CD with GitHub Actions
Automate both builds:
name: Deploy
on:
push:
tags: ['v*']
jobs:
ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
- run: flutter build ipa --release
- uses: apple-actions/upload-testflight-build@v1
with:
app-path: build/ios/ipa/*.ipa
android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
- run: flutter build appbundle --release
- uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_KEY }}
packageName: com.yourname.yourapp
releaseFiles: build/app/outputs/bundle/release/app-release.aab
track: production
Post-Deployment
After both stores approve your app:
Set up crash reporting (Firebase Crashlytics)Configure analyticsSet up feature flags for gradual rolloutsMonitor store reviews for bug reportsThe whole process takes about 2-3 hours for the first time. After that, tagging a release triggers automatic deployment to both stores.