Release build.
Your ids, your signing, the store checklist.
What to change before your first upload, how to sign the Android and iOS builds, and what the stores ask of an AI chat app. A release build is the file you upload to Google Play or the App Store. Do the ids first: Firebase and the stores register your app under them.
01Ids to replace before publishing
| What | Where |
|---|---|
Application id / bundle id com.mikodes.museai | Android: namespace and applicationId in android/app/build.gradle.kts, and move android/app/src/main/kotlin/com/mikodes/museai/MainActivity.kt to the folder of your id with the matching package line. iOS: Xcode → Runner target → General → Bundle Identifier (PRODUCT_BUNDLE_IDENTIFIER; the test target uses <your id>.RunnerTests). Then run flutterfire configure again, which rewrites lib/firebase_options.dart. |
| App name under the icon | android:label in AndroidManifest.xml, CFBundleDisplayName in Info.plist, web/index.html, web/manifest.json |
| Icons | /usr/bin/python3 tool/gen_icons.py or your own PNGs (Customization) |
| Google sign-in URL scheme (iOS) | ios/Runner/Info.plist → CFBundleURLTypes: replace com.googleusercontent.apps.REPLACE-WITH-YOUR-REVERSED-CLIENT-ID with your REVERSED_CLIENT_ID (iOS sign-in) |
| AdMob app ids | AndroidManifest.xml and Info.plist (Ads), then tool/check_ad_ids.sh --release |
| Store product ids | Set in the console, not in the code: plan products on Plans (example plan pro_monthly, pro_yearly), and remove_ads, credits_small, credits_medium, credits_large on Store & purchases (In-app purchases) |
| Version | version: 2.0.0+200 in pubspec.yaml (name + build number). Raise the build number for every upload. |
If you publish this as an update of an app you already have in the stores, keep your existing ids instead (Upgrading from 1.x).
02Android signing
- Create an upload key(once, keep it and its passwords safe; losing it blocks updates until Google resets it):
keytool -genkey -v -keystore android/app/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias uploadTerminal: macOS or Linux as shown; on Windows use WSL or Git Bash (how).
- Create
app/android/key.properties(git-ignored, never commit it):storePassword=<your store password> keyPassword=<your key password> keyAlias=upload storeFile=upload-keystore.jks - Build
flutter build appbundle --release --dart-define=API_BASE_URL=https://<region>-<project-id>.cloudfunctions.net/apiTerminal: macOS or Linux as shown; on Windows use WSL or Git Bash (how).
The bundle is inbuild/app/outputs/bundle/release/.
build.gradle.kts signs release builds with key.properties. Without the file it falls back to the debug key: fine for flutter run --release, but Google Play refuses such a build.
Google sign-in on Android needs the SHA-1 and SHA-256 fingerprints of your keys in Firebase console → Project settings → your Android app (add the upload key and, after the first upload, the app signing key from Play Console → Setup → App signing). Print the upload key's with keytool -list -v -keystore android/app/upload-keystore.jks -alias upload.
03iOS signing and capabilities
- Open the workspace
open ios/Runner.xcworkspace(not the.xcodeproj). - TeamRunner target → Signing & Capabilities → pick your own team. The source ships without one.
- CapabilitiesAdd Push Notifications (Background Modes → Remote notifications is already in
Info.plist) and, if Apple sign-in is on, Sign in with Apple. Sign in with Apple also needs the Apple provider configured in Firebase Authentication. - Build
flutter build ipa --release --dart-define=API_BASE_URL=https://<region>-<project-id>.cloudfunctions.net/apiTerminal: macOS or Linux as shown; on Windows use WSL or Git Bash (how).
Upload the.ipafrombuild/ios/ipa/with Xcode's Organizer or Transporter. iOS builds need a Mac.
04iOS sign-in: Google URL scheme and Apple
On iOS the app signs in with Google through Firebase Authentication (signInWithProvider): a Google sign-in page opens and then returns to the app through a URL scheme. Without your scheme in Info.plist the page cannot return and Google sign-in fails or crashes. Android needs no URL scheme (it needs the SHA fingerprints above).
- Enable Google firstFirebase console → Authentication → Sign-in method → Google → Enable (Installation). Enabling it creates the iOS OAuth client. If you ran
flutterfire configurebefore that, run it again so thatios/Runner/GoogleService-Info.plistcontains the client. - Copy REVERSED_CLIENT_IDOpen
app/ios/Runner/GoogleService-Info.plist(any text editor, or Xcode) and copy the value of the keyREVERSED_CLIENT_ID. It looks likecom.googleusercontent.apps.1234567890-abcdefg. The same file is also in Firebase console → Project settings → General → your iOS app → GoogleService-Info.plist (download). - Paste it into Info.plistOpen
app/ios/Runner/Info.plist, findCFBundleURLTypes(the entry namedgoogle-sign-in) and replace the placeholdercom.googleusercontent.apps.REPLACE-WITH-YOUR-REVERSED-CLIENT-IDwith your value. Keep only one value per line; the source ships with this placeholder and no real id. - Or in XcodeThe same entry is in Xcode → Runner target → Info tab → URL Types → the entry with identifier
google-sign-in→ URL Schemes. Editing it there writes the sameInfo.plist. - If your file has no REVERSED_CLIENT_IDGoogle is not enabled in Firebase yet, or the plist is older than that: do step 1 and download it again. Firebase also accepts the iOS app's Encoded App ID (Firebase console → Project settings → your iOS app, it starts with
app-1-) as the URL scheme; add it as a second string underCFBundleURLSchemesif Firebase asks for it in an error message. - CheckBuild, tap Continue with Google: the Google page opens and comes back to the app signed in. "Custom URL scheme ... is not registered" in the Xcode console means the value does not match
REVERSED_CLIENT_ID.
Sign in with Apple needs no URL scheme on iOS: it uses Apple's native sheet. It needs the Sign in with Apple capability (Runner target → Signing & Capabilities, see above) and the Apple provider enabled in Firebase Authentication. E-mail and password sign-in needs nothing on iOS. The app opens no other app by URL scheme, so LSApplicationQueriesSchemes is not needed.
05Push notifications
- iOS: create an APNs authentication key (Apple Developer → Certificates, IDs & Profiles → Keys, enable Apple Push Notifications service) and upload it in Firebase console → Project settings → Cloud Messaging → your iOS app.
- Android: no extra step;
google-services.jsonfromflutterfire configureis enough. - The app registers its token with the backend and subscribes to the topics
allandpro(any plan) orfree. Campaigns from the console go to those topics.
06Permission texts (iOS)
Info.plist carries the texts iOS shows when the app asks for access: microphone and speech recognition (dictation, voice mode, voice notes, recordings), camera and photo library (attachments, importing videos, saving images and exported videos), and tracking (ads consent). Adjust the wording to your app; keep them accurate, because App Review checks them.
07Store checklist for an AI chat and image app
tool/check_ad_ids.sh --releasepasses (or you do not use AdMob).- The build uses your
API_BASE_URLand notDEMO_MODE. - Console: Terms and Privacy URLs set, Status has no blockers, at least one free model live.
- Age rating in both stores matches the console's Minimum age (default 17+, the App Store rating for unrestricted AI chat). The in-app age check is a self-confirmation checkbox; do not describe it as age verification in your listing.
- Video export, auto captions and natural voices tested on a real Android and iOS device (export does not run on the web).
- Your privacy policy names the AI, voice and video providers you use, says conversations stay on the device and that message text, prompts and audio are forwarded to the provider, that image and video prompts are stored with the generated files, and describes what account deletion keeps (Privacy).
- App Store privacy labels and the Google Play Data safety form match: user id, purchase history, usage data, and advertising data if ads are on.
- Report button and review queue in place (they are): stores expect a way to report AI content and your review of reports.
- Account deletion inside the app (Settings → Delete account) is present, as both stores require.
- App name, icon and store texts use no third-party AI trademark.
- If you sell plans or credits: products created, verification set up (In-app purchases), Restore purchases works.
- If Discover is on: you checked each enabled feed publisher's terms (Discover).