Release build
sign, build, publish.
The pre-release checklist, Android signing, the build commands for Google Play and the App Store, and the optional web demo.
01Before the first release
- Your own Firebase project, deployed, with
flutterfire configuredone (Firebase setup) - Your own application id and bundle id (Rebranding)
- Your own AdMob app ids in
AndroidManifest.xmlandInfo.plist(Ads) - Ad network unit ids and the verification secret in the console for every network you use; the callback URL set in each network; one real video credited
- Only the ad placements you want switched on, with their caps (Placements)
- Each enabled offerwall or survey: one test postback credited (testing)
- If the cash wallet is on: the app renamed from the default "Watch And Earn" (why); legal review done, payout terms published, one payout tested end to end, payout accounts funded, iOS left off unless you checked Apple's rules (Switching the wallet on)
- iOS:
CFBundleLocalizationsstill lists every language you ship (all 9 out of the box; Languages) - UMP consent messages published in AdMob → Privacy & messaging
- App Check registered and enforced;
ENFORCE_APP_CHECKistrue - Privacy policy, terms and rewards rules URLs in console → Legal; Status page without warnings
- Android release signing set up (below)
- If you build with a non-default region:
--dart-define=FUNCTIONS_REGION=…on every build
02Version number
app/pubspec.yaml has version: 4.0.0+400: 4.0.0 is the version users see, 400 the build number. Raise the build number for every upload; both stores refuse a number they have already seen.
03Android signing
The package signs release builds with the debug key so flutter run --release works out of the box (app/android/app/build.gradle.kts, buildTypes.release). Google Play refuses debug-signed apps, so create your own upload key.
- Create the keyKeep the file and the passwords safe and outside git. Losing them means you cannot update the app without Google's help.
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload - Create
app/android/key.propertiesstorePassword=<password> keyPassword=<password> keyAlias=upload storeFile=<absolute path to upload-keystore.jks> - Use it in
app/android/app/build.gradle.ktsFollow Flutter's "Build and release an Android app" guide (Kotlin DSL): loadkey.properties, add asigningConfigs { create("release") { … } }block and setsigningConfig = signingConfigs.getByName("release")inbuildTypes.releaseinstead of the debug one. - Fingerprints to FirebaseAdd the SHA-1 and SHA-256 of your upload key, and of the app signing key shown in Play Console → Setup → App signing, in Firebase Project settings. Google sign-in and Play Integrity need them.
04Build for Google Play
cd app
flutter build appbundle # add --dart-define=FUNCTIONS_REGION=... if not us-central1
Upload app/build/app/outputs/bundle/release/app-release.aab to Play Console, first to Internal testing. Test sign-in, a rewarded video, the wheel, a quiz and account deletion on the internal build before you promote it.
05Build for the App Store
- SigningOpen
app/ios/Runner.xcworkspacein Xcode → Runner → Signing & Capabilities. Choose your team. Add Sign in with Apple, Push Notifications, Background Modes → Remote notifications and In-App Purchase. Minimum Deployments is already 15.0. - Build
cd app flutter build ipa - UploadUpload
app/build/ios/ipa/*.ipawith Apple's Transporter app or from Xcode's Organizer, then test through TestFlight.
06Rename the app before the cash wallet goes on
The package ships with the name "Watch And Earn" in console → Brand (Product name), android:label in app/android/app/src/main/AndroidManifest.xml, CFBundleDisplayName and CFBundleName in app/ios/Runner/Info.plist, and the web <title> and manifest.json. Next to a cash wallet, that name reads like "watch ads, earn money", which is exactly what AdMob's rewards policy and the stores' deceptive-behaviour rules forbid. Before you switch the cash wallet on, give the app your own name, icon and store listing (Rebranding).
- Never market the app, in its name, icon, screenshots, store text or ads, as a way to earn money by watching ads, playing games or collecting points.
- Describe cash truthfully: rewards from completed partner offers and surveys, with a minimum, a hold and an approval step.
- Keep the in-app wallet notice and "How cash works" consistent with that (Platform rules).
07Store listing
- Never promise income, and never suggest that watching ads, playing games or collecting points pays money. With the wallet off, describe a rewards app with points and badges. With the wallet on, say that cash rewards come from completed partner offers and surveys, with a minimum, a hold and an approval step (Google Play).
- Answer the content rating questionnaire, the Data safety form (Play) and the App Privacy section (Apple) truthfully.
- Give reviewers a way in: guest sign-in works without an account.
08Optional: host the web demo
The web target is meant for demo mode (simulated ads, in-memory backend): the ad SDKs and store purchases do not run on the web. It is useful as a public preview, not as the product.
cd app
flutter build web --dart-define=DEMO_MODE=true # output in app/build/web, any static host
09The console in production
Run it over HTTPS, keep ADMIN_SECRET_KEY and the data/ folder (or your Postgres) backed up, and give team members the lowest role they need. See Deploy options.