Android product flavors (.dev/.staging suffixes, prod clean) + per-flavor
Dart entrypoints, dart-define env files, and per-flavor Firebase config for
both platforms across 3 projects (halobestie-clone-dev / my-bestie-876ec /
my-bestie-production).
- Android: flavorDimensions("env") + productFlavors; @string/app_name label;
per-flavor src/<flavor>/google-services.json (clients verified to match each
applicationId).
- iOS: customer app re-based to the EXISTING App Store identity
com.asc.hallobestie (dev/staging suffix it; ships as an update to the live
app). mitra is a new app (com.mybestie.mitra). Per-flavor plists staged in
ios/config/<flavor>/; Xcode scheme wiring deferred (Mac follow-up).
- firebase_options_{dev,staging,prod}.dart filled with real android + iOS
values (regenerated from the native config files).
- BUILD_FLAVORS.md per app documents flavor table, build commands, iOS
identity decision, and the remaining iOS Xcode steps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
122 lines
6.4 KiB
Markdown
122 lines
6.4 KiB
Markdown
# Build Flavors — mitra_app (Android)
|
|
|
|
The mitra_app has three Android build flavors: **dev**, **staging**, **prod**.
|
|
Each has its own `applicationId`, backend URL, app display name, Dart entrypoint,
|
|
Firebase Dart options, and `google-services.json` source set — so all three can
|
|
be installed side-by-side on one device.
|
|
|
|
> Scope note: this is **Android + Dart + env-files** only. iOS Xcode schemes are
|
|
> a separate follow-up and are NOT set up yet.
|
|
|
|
## Flavor matrix
|
|
|
|
| Flavor | applicationId | API_BASE_URL | App name | Entrypoint | env file |
|
|
|---------|-----------------------------|-------------------------------------------|---------------------------|-----------------------|-------------------|
|
|
| dev | `com.mybestie.mitra.dev` | `http://192.168.88.247:3000` | Mitra HaloBestie Dev | `lib/main_dev.dart` | `env/dev.json` |
|
|
| staging | `com.mybestie.mitra.staging`| `https://staging-api.halobestie.com` ⚠️ | Mitra HaloBestie Staging | `lib/main_staging.dart`| `env/staging.json`|
|
|
| prod | `com.mybestie.mitra` | `https://api.halobestie.com` | Mitra HaloBestie | `lib/main_prod.dart` | `env/prod.json` |
|
|
|
|
⚠️ The staging `API_BASE_URL` is a **placeholder** — confirm the real staging
|
|
host and update `env/staging.json` + `lib/firebase/firebase_options_staging.dart`.
|
|
|
|
The `applicationId` suffix is applied in `android/app/build.gradle.kts`
|
|
(`applicationIdSuffix = ".dev"` / `".staging"`; prod has none). The app name is
|
|
emitted per flavor via `resValue("string", "app_name", "...")` and read by
|
|
`android/app/src/main/AndroidManifest.xml` through `android:label="@string/app_name"`.
|
|
|
|
## Build / run commands
|
|
|
|
Every command MUST pass `--flavor`, a matching `-t` entrypoint, and
|
|
`--dart-define-from-file` for the env. Examples:
|
|
|
|
### Run (debug, on a device/emulator)
|
|
```bash
|
|
flutter run --flavor dev -t lib/main_dev.dart --dart-define-from-file=env/dev.json
|
|
flutter run --flavor staging -t lib/main_staging.dart --dart-define-from-file=env/staging.json
|
|
flutter run --flavor prod -t lib/main_prod.dart --dart-define-from-file=env/prod.json
|
|
```
|
|
|
|
### Build APK
|
|
```bash
|
|
flutter build apk --flavor dev -t lib/main_dev.dart --dart-define-from-file=env/dev.json
|
|
flutter build apk --flavor staging -t lib/main_staging.dart --dart-define-from-file=env/staging.json
|
|
flutter build apk --flavor prod -t lib/main_prod.dart --dart-define-from-file=env/prod.json
|
|
```
|
|
|
|
### Build App Bundle (Play Store)
|
|
```bash
|
|
flutter build appbundle --flavor prod -t lib/main_prod.dart --dart-define-from-file=env/prod.json
|
|
```
|
|
|
|
A bare `flutter run` (no `-t`) still works — `lib/main.dart` delegates to the
|
|
dev bootstrap — but it builds with no flavor selected on Android, so prefer the
|
|
explicit commands above.
|
|
|
|
## ⚠️ CRITICAL warnings
|
|
|
|
1. **`--flavor` is now mandatory for builds.** Once product flavors exist, a
|
|
bare `flutter build apk` (without `--flavor`) FAILS with a Gradle error
|
|
(no default flavor). Every build/run command must specify `--flavor` and the
|
|
matching `-t lib/main_<flavor>.dart` entrypoint.
|
|
|
|
2. **The dev applicationId changed to `com.mybestie.mitra.dev`.** Any tooling
|
|
that references the old package id must be updated when running the dev
|
|
flavor:
|
|
- `adb` commands: `adb shell pm clear com.mybestie.mitra.dev`,
|
|
`adb shell am start ... com.mybestie.mitra.dev/...`, etc.
|
|
- Maestro flows: `appId: com.mybestie.mitra.dev`.
|
|
- Any deeplink / FCM tooling keyed on the package name.
|
|
Prod keeps `com.mybestie.mitra`; staging is `com.mybestie.mitra.staging`.
|
|
|
|
## Firebase config — STATUS: configured ✅ (2026-06-04)
|
|
|
|
Firebase init is **Dart-side** (`Firebase.initializeApp(options:)` in
|
|
`lib/bootstrap.dart`), driven by the per-flavor
|
|
`lib/firebase/firebase_options_<flavor>.dart`. The mitra app is a **brand-new
|
|
app** on both platforms (no legacy App Store identity), so the iOS bundle base
|
|
is `com.mybestie.mitra` — unlike the customer app, which inherits
|
|
`com.asc.hallobestie`.
|
|
|
|
All apps registered + config in place across 3 projects (one per env):
|
|
|
|
| Env | Firebase project | Android applicationId | iOS bundle ID |
|
|
|---------|------------------------|-------------------------------|------------------------------|
|
|
| dev | `halobestie-clone-dev` | `com.mybestie.mitra.dev` | `com.mybestie.mitra.dev` |
|
|
| staging | `my-bestie-876ec` | `com.mybestie.mitra.staging` | `com.mybestie.mitra.staging` |
|
|
| prod | `my-bestie-production` | `com.mybestie.mitra` | `com.mybestie.mitra` |
|
|
|
|
In place and verified:
|
|
- `android/app/src/<flavor>/google-services.json` — all 3, client matches the flavor applicationId.
|
|
- `ios/config/<flavor>/GoogleService-Info.plist` — all 3, bundle IDs verified.
|
|
- `lib/firebase/firebase_options_{dev,staging,prod}.dart` — real android + iOS values, no placeholders.
|
|
|
|
### Regenerating after any ID / key change
|
|
```bash
|
|
flutterfire configure --project=halobestie-clone-dev --out=lib/firebase/firebase_options_dev.dart
|
|
flutterfire configure --project=my-bestie-876ec --out=lib/firebase/firebase_options_staging.dart
|
|
flutterfire configure --project=my-bestie-production --out=lib/firebase/firebase_options_prod.dart
|
|
```
|
|
|
|
### Still TODO — iOS only (Mac/Xcode)
|
|
- [ ] iOS Xcode schemes + build-phase copy script to select the right
|
|
`GoogleService-Info.plist` per flavor (until then iOS bundles only
|
|
`ios/Runner/GoogleService-Info.plist`). See `ios/config/README.md`.
|
|
|
|
> The Google Services Gradle plugin is **not** applied in this app — Android
|
|
> Firebase init is Dart-side. The `src/<flavor>/google-services.json` files are
|
|
> laid out for if/when that plugin is added.
|
|
|
|
## File map
|
|
|
|
| File | Purpose |
|
|
|---|---|
|
|
| `android/app/build.gradle.kts` | `flavorDimensions "env"` + `productFlavors` (id suffix + app_name) |
|
|
| `android/app/src/main/AndroidManifest.xml` | `android:label="@string/app_name"` |
|
|
| `android/app/src/dev/google-services.json` | dev Firebase config |
|
|
| `android/app/src/{staging,prod}/google-services.json.README` | placeholders — drop real json here |
|
|
| `lib/bootstrap.dart` | shared `bootstrap()` + `App` widget |
|
|
| `lib/main.dart` | bare entrypoint → delegates to dev |
|
|
| `lib/main_{dev,staging,prod}.dart` | per-flavor entrypoints |
|
|
| `lib/firebase/firebase_options_{dev,staging,prod}.dart` | per-flavor Dart Firebase options |
|
|
| `env/{dev,staging,prod}.json` | dart-define values (`API_BASE_URL`, `FLAVOR`) |
|