feat(build): add dev/staging/prod flavors for client_app + mitra_app
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>
This commit is contained in:
121
mitra_app/BUILD_FLAVORS.md
Normal file
121
mitra_app/BUILD_FLAVORS.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# 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`) |
|
||||
Reference in New Issue
Block a user