Flutter tutorial
Publish a Flutter app: release build and store checklist
This guide prepares a Flutter project for App Store and Google Play submission through Shiptavio. It covers identity, permissions, release builds, the files to send, and the failures that most often block a store upload.
By Shiptavio · Updated 26 October 2026 · 10 min read · Flutter
1. Confirm the app is a fit
Shiptavio publishes free apps under the Apple Developer and Google Play organization accounts of our Malaysia-based organization. Check the commercial and category limits before you spend time on the build.
- The app is free. No paid download, in-app purchase, or digital subscription.
- The app is not in a prohibited category such as gambling, crypto or finance, medical, VPN, adult content, or government services.
- Every API uses production HTTPS. Localhost, private LAN addresses, and test endpoints are rejected.
- You own the code, name, logo, and content.
- You can provide a demo account if the app has a login.
Read the prohibited apps page before you start. A store rejection is not the only risk; the publisher account has to stay in good standing.
2. Set the app identity and version
Set the bundle identifier and package name once. Changing either after the first publish creates a separate app in the store. The version line in pubspec.yaml holds both the version name and the build number.
- iOS bundle identifier: set it in Xcode or in the Runner target settings.
- Android applicationId: set it in android/app/build.gradle or build.gradle.kts.
- Build number: increment the value after the + for every store upload.
- Keep the app name, icon, and splash screen consistent with the store listing.
name: my_app
version: 1.2.0+42// android/app/build.gradle.kts
android {
defaultConfig {
applicationId = "com.yourcompany.myapp"
versionCode = 42
versionName = "1.2.0"
}
}3. Add permissions and native settings
A Flutter plugin can add native permissions without making the required declaration obvious. Check both platforms before you build.
- Add an iOS usage description in ios/Runner/Info.plist for every protected resource the app uses: camera, photo library, microphone, location, contacts, notifications, or tracking.
- Add Android permissions to android/app/src/main/AndroidManifest.xml, and keep the runtime permission requests in Dart.
- If the app uses deep links, configure the URL scheme and associated domains or app links.
- If the app supports tablets or landscape, check the iOS device family and Android screen support.
- Remove test keys, debug banners, and test data from release builds.
4. Prepare icons, screenshots, and listing text
The stores review the listing as closely as the build. Use real screenshots from the app, not website mockups.
- iOS app icon: 1024 x 1024 px, no transparency.
- Android app icon: 512 x 512 px. Android feature graphic: 1024 x 500 px.
- iPhone screenshots at a current store size, plus iPad screenshots if the app runs on iPad.
- Android screenshots and a short description within the current character limits.
- A privacy policy, support URL, support email, and a working demo account if the app has a login.
- Account deletion inside the app if users can create an account.
Artwork generated by flutter_launcher_icons or flutter_native_splash is fine, but check the final assets at full size before you upload them.
5. Run the Flutter checks
Run the same checks a release build will hit. Fix analyzer errors and failing tests before you send the source.
- Run the app on a small Android screen and a recent iPhone.
- Test a denied permission, a failed network request, and the offline state.
- Sign in with the demo account and complete the main task.
- Check the Android back button and the iOS back gesture.
flutter pub get
flutter analyze
flutter test6. Run the release builds
A store build needs a signed iOS archive and an Android App Bundle. Shiptavio runs these commands on its Mac, but a local compile check catches project errors early.
- If you use flavors, add --flavor and the matching target file.
- If you pass configuration with --dart-define, send the exact values. They are compiled into the app and are not secret.
- For a compile check without signing, use flutter build ios --release --no-codesign.
- Do not send the build/ or .dart_tool/ output.
flutter build ipa --releaseflutter build appbundle --releaseDo not put private API keys in --dart-define. Anything compiled into the app can be extracted.
7. Package the source
Send readable source. A repository URL or a zip of the project is enough. The native folders must be present.
- Include ios/, android/, pubspec.yaml, pubspec.lock, lib/, and assets.
- Leave out build/, .dart_tool/, ios/Pods/, android/.gradle/, .env files, keystores, and private keys.
- If you use a private repository, add the Shiptavio account shown in the submission form as a read-only collaborator.
- The source limit is 200 MB.
git add ios android pubspec.lock
git commit -m "Prepare native projects"
git archive --format=zip -o my-app-source.zip HEAD8. Submit to Shiptavio
Create the app record, choose Flutter, and add the source and store details. A person reviews the project before the build starts.
- Choose iOS, Android, or both. Apple platforms are optional and use a separate platform credit.
- Add the exact build command, flavor, and non-secret environment values.
- Upload the icon, screenshots, feature graphic, and listing text.
- Complete the age rating, privacy, data safety, and review contact sections.
- Add a demo account and reviewer notes if the app needs them.
9. Updates and common failures
Your first publish uses one release credit. Each later update uses one more. A store rejection or a fix to the same release does not use an extra credit.
- Missing ios/ or android/: run flutter create . in the project root, then commit both folders.
- CocoaPods failure: run pod repo update and pod install in ios/ on a Mac if you can, or send the full error.
- Missing usage description: the iOS build may pass but App Review will reject the app when a permission prompt appears.
- Build number not incremented: both stores reject a duplicate build number.
- Minimum SDK mismatch: check the Android minSdkVersion required by your plugins.
- Do not change the bundle identifier between updates unless you intend to create a new app.
Common questions
Can I compile-check a Flutter iOS build without a Mac?
Should I send build/ or .dart_tool/?
How do I handle different API URLs for staging and production?
Do I need to send a keystore?
Can I use Flutter flavors?
What happens after I submit?
Related guides
Publish a Flutter app
The service overview, scope, and pricing.
Expo publishing tutorial
For React Native projects that use Expo.
React Native publishing tutorial
For bare React Native CLI projects.
How to submit
The dashboard flow from account creation to store review.
Compare publishing options
Shiptavio, Expo EAS, Codemagic, and Fastlane.
Ready to send the project?
Register the app and add the source. A person reviews the project before the build starts.