Release build
sign, build, publish.
The pre-release checklist, Android signing, the build commands for Google Play and the App Store, review notes for a finance app, and the privacy forms.
01Before the first release
- Backend deployed in your Firebase project and
flutterfire configuredone (Firebase backend, Installation) - Your own application id, bundle id and App Group (Rebranding)
- Console over HTTPS; Legal URLs set; a CoinGecko Demo key or better; Status without blockers (Operator console)
- APNs key uploaded to Firebase; a test alert received on a real iPhone and Android phone (Alerts and push)
- If you use AdMob: your own app ids in
AndroidManifest.xmlandInfo.plist, UMP messages published (Ads) - If you sell purchases: products created in both stores, verification set up, one sandbox purchase verified (Purchases)
- Android release signing set up (below)
- Every build uses
--dart-define=API_BASE_URL=…with your API
02Version number
app/pubspec.yaml has version: 2.0.0+200: 2.0.0 is the version users see, 200 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 FirebaseIf you enable Google sign-in, add the SHA-1 and SHA-256 of your upload key and of the app signing key (Play Console → Test and release → App integrity) in Firebase Project settings → your Android app.
04Build for Google Play
cd app
flutter build appbundle --dart-define=API_BASE_URL=https://<region>-<your-project-id>.cloudfunctions.net/api
Upload app/build/app/outputs/bundle/release/app-release.aab to Play Console, first to Internal testing. On the internal build, test the markets, a coin chart, an alert push, a wallet lookup, both widgets and, if enabled, an ad and a test purchase.
05Build for the App Store
- SigningOpen
app/ios/Runner.xcworkspacein Xcode. Choose your team for Runner and CryptoTrackerWidget. Runner already has Push Notifications, Sign in with Apple (the sign-in screen offers it on iOS), the App Group and the Remote notifications background mode (app/ios/Runner/Runner.entitlements). Enable Sign in with Apple for your App ID too (Xcode's automatic signing does this). Add In-App Purchase if you sell purchases. Minimum Deployments is 15.0. - Build
cd app flutter build ipa --dart-define=API_BASE_URL=https://<region>-<your-project-id>.cloudfunctions.net/api - UploadUpload
app/build/ios/ipa/*.ipawith Apple's Transporter app or from Xcode's Organizer, then test through TestFlight (set the console's App Store environment to Sandbox while you test purchases).
06Store review notes for a finance app
Crypto apps get extra attention in review. Describe honestly what the app is:
- A tracker only. Market data, a manual portfolio, price alerts, news and read-only lookups of public addresses. No wallet, no keys, no trading, no transfers, no custody.
- No investment advice. Summaries describe data and are labelled "AI-generated" or "Automatic summary" with a disclaimer.
- No sign-in needed. Reviewers can use everything right away; the app creates an anonymous account in the background.
- Paid content and links, if you enabled them: sponsored items are labelled "Sponsored", exchange links "Affiliate link" with a disclosure.
Example review note:
Cryptocurrency price tracker. Read-only: market data, a manual portfolio, price alerts and
balance lookup of public addresses. The app holds no keys and cannot send, trade or swap.
Summaries are informational, labelled and not financial advice. No sign-in is required.
- Google Play: complete the Financial features declaration in Play Console → App content, the content rating and the target audience. Check Play's policy on crypto and financial services for each country you publish in, especially if affiliate links to exchanges are on.
- App Store: App Review Guidelines section 3.1.5 covers cryptocurrencies. A tracker that does not facilitate trading or transfers is the simplest case; affiliate links to exchanges can draw questions, so describe them in the review notes.
- Store listing: no promises of profit, no "signals", no price predictions.
- Account deletion: both stores require in-app account deletion for apps that let users create an account. The app has it: Settings → Delete account (what is deleted and what is kept). Google Play also asks for a web link where users can request deletion; provide one on your own site (for example a page that tells users to e-mail you). Check the current policies before you submit.
07Privacy forms
Answer Google Play's Data safety form and Apple's App Privacy details from what your build really does. What the code sends to your backend and Firebase:
| Data | Where | Why |
|---|---|---|
| Anonymous Firebase user id; e-mail or Google/Apple identity if the user signs in | Firebase Auth, users/{uid} | Alerts, purchases, optional cloud backup |
| Platform, language, currency, last seen time | users/{uid} | Push texts, counts in the console |
| Push token | users/{uid}/devices | Price alerts, campaigns |
| Price alerts | users/{uid}/alerts | Server-side evaluation |
| Purchase tokens and order ids, price | purchases, revenueEvents | Verification, entitlements |
| Public wallet addresses | Sent to your API for each lookup and to the RPC provider; not stored on the server | Balance lookup |
| Watchlist, portfolios, wallets | On the device; in users/{uid}/sync only with cloud backup | The app's features |
| Advertising id and ad data | The ad networks you enable | Ads |
Deletion: Settings → Delete account removes the account and its server data, but keeps purchase and revenue records for accounting (details). Say so in the privacy policy and in the stores' deletion questions.
Write a privacy policy that matches, host it, and enter its URL in Console → Legal and in both store listings.
08Optional: host the web demo
The web target is for demo mode only. It needs the API next to it at /api (or another API_BASE_URL).
cd app
flutter build web --dart-define=DEMO_MODE=true --dart-define=API_BASE_URL=/api # output in app/build/web
Serve app/build/web from a static host and route /api/v1/* to an instance of the API (for example npm run dev:api behind a reverse proxy, or the Cloud Function through a Hosting rewrite). Do not point a public demo at your production project.