Shipping to the App Store or Play Store is a checklist, not a mystery. Work through each step in order and your app lands on both stores.
Android is the friendlier of the two. Start there if it's your first release. iOS has more gates (certificates, provisioning profiles, a stricter review), but the path is well-worn once you've done it a couple of times.
Android
1. App icon
Put a 1024x1024 PNG at assets/icon.png. Install flutter_launcher_icons and add to pubspec.yaml:
flutter_launcher_icons:
android: "launcher_icon"
ios: false
image_path: "assets/icon.png"
adaptive_icon_foreground: "assets/icon.png"
adaptive_icon_background: "#FFFFFF"Run the generator and Android adaptive icons show up on your home screen.
dart run flutter_launcher_icons2. App ID
Every app needs a globally unique ID. Flutter defaults to com.example.yourapp, which you must change before submitting. Edit android/app/build.gradle:
android {
namespace = "app.yourname.yourapp"
defaultConfig {
applicationId = "app.yourname.yourapp"
minSdk = 23
targetSdk = 35
}
}Google bumps the required targetSdk every year. If Play rejects your build for targeting an older SDK, this is where you raise the number.
3. Keystore
Every Android release has to be signed. Generate a keystore once and use it forever.
keytool -genkey -v -keystore ~/upload-keystore.jks \
-keyalg RSA -keysize 2048 -validity 10000 \
-alias uploadBack up the .jks file and the passwords to a password manager before you do anything else. Lose them and you can't update your app. Ever. New version means a new listing.
Create android/key.properties (and add it to .gitignore):
storePassword=...
keyPassword=...
keyAlias=upload
storeFile=/Users/you/upload-keystore.jksReference it in android/app/build.gradle:
def keystoreProperties = new Properties()
def f = rootProject.file('key.properties')
if (f.exists()) keystoreProperties.load(new FileInputStream(f))
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile']
? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release { signingConfig signingConfigs.release }
}4. Build
Google Play wants an AAB (Android App Bundle), not an APK.
flutter build appbundle --releaseThe output is at build/app/outputs/bundle/release/app-release.aab.
5. Play Console
Register at play.google.com/console. There's a one-time $25 fee.
Create a new app, then work through the dashboard checklist: privacy policy, app access, ads, content rating, target audience, data safety. Each one has a form to fill in.
Fill the store listing: category, short and full description, screenshots, contact email. Upload the .aab to Production, create a release, and submit. Review takes hours to a couple of days.
iOS
1. Requirements
- A Mac with Xcode installed (you can't build iOS apps on Windows or Linux).
- An Apple Developer account ($99/year).
2. App icon
Configure the same flutter_launcher_icons for iOS. iOS icons can't have transparency, so remove_alpha_ios: true fills transparent pixels with white.
flutter_launcher_icons:
android: false
ios: true
image_path: "assets/icon.png"
remove_alpha_ios: true3. Bundle ID
Open ios/Runner.xcworkspace in Xcode. Under Runner → General, set the Bundle Identifier to something in reverse-domain format (app.yourname.yourapp). This is the permanent ID for your app on the App Store.
4. Signing
In Xcode, Signing & Capabilities → check "Automatically manage signing" → pick your team. Xcode creates the certificates and provisioning profiles for you. If it errors out, Xcode → Settings → Accounts, make sure you're signed in with your Developer Program Apple ID.
5. Build
flutter build ipa --release6. App Store Connect
Go to appstoreconnect.apple.com and create a new app. Pick iOS for the platform, fill in the name, pick your Bundle ID, and give it an SKU (any unique string for your records).
7. Upload
In Xcode: Window → Organizer → select your archive → Distribute App → App Store Connect → Upload. Or download Transporter from the Mac App Store and drag the .ipa file in.
The build takes a few minutes to process. It appears in App Store Connect under TestFlight once it's ready.
8. Listing
Fill in screenshots (at minimum 6.7" and 5.5" iPhone), description, keywords (100 char limit), support URL, privacy policy URL, category.
Under App Review Information, give Apple any credentials they need to test your app. If your app needs a login, create a test account for them.
9. Submit
Select the uploaded build, click Submit for Review. Apple reviews in 24 to 48 hours.
Common rejection reasons: missing privacy policy, unclear app purpose, login required without test credentials, broken features. Fix and resubmit.