Build flavors
Oter has two independent flavor systems, one per build pipeline. They share the same names (dev, qa, prod) but are wired up differently.
Android (androidApp/) — real product flavors
Defined in androidApp/build.gradle.kts under flavorDimensions += "environment". Each flavor injects its own BASE_URL, sockets host/port, app name, and applicationId suffix via buildConfigField / resValue.
| Flavor | Default? | App ID suffix | App name | BASE_URL |
|---|---|---|---|---|
dev | yes | .dev | Oter DEV | http://192.168.5.100:8080/api/v1/ |
qa | no | .qa | Oter QA | https://api-qa.estebanruano.com/api/v1/ |
prod | no | — | Oter | https://api.estebanruano.com/api/v1/ |
The
devBASE_URL points at a LAN IP so a physical Android device on the same network can reach a local server. Change it inbuild.gradle.ktsif your host IP differs.
Commands
Gradle task pattern is <task><Flavor><BuildType>:
# Install debug build of a flavor on a connected device/emulator
./gradlew :androidApp:installDevDebug
./gradlew :androidApp:installQaDebug
./gradlew :androidApp:installProdDebug
# Release builds (signed when keystore.properties is configured)
./gradlew :androidApp:assembleProdRelease
./gradlew :androidApp:bundleProdRelease # AAB for Play Storedev is isDefault = true, so assembleDebug resolves to assembleDevDebug.
Compose Multiplatform (composeApp/ — desktop, iOS, wasmJS) — Gradle-property switch
KMP targets don’t support Android-style flavors, so composeApp simulates them with two Gradle properties read at configure time and baked into a generated BuildConfig.kt:
| Gradle property | Default | Becomes |
|---|---|---|
oter.flavor | dev | BuildConfig.FLAVOR ("dev", "qa", "prod") |
oter.release | false | BuildConfig.IS_RELEASE (Boolean) |
Generation lives in composeApp/build.gradle.kts (registerBuildConfigTask) and produces BuildConfig.kt for desktopMain, wasmJsMain, and iosMain. Each platform’s *Constants.kt (e.g. DesktopConstants.kt) then maps FLAVOR to per-env BASE_URL / sockets host / sockets port:
| Flavor | BASE_URL | Sockets host:port |
|---|---|---|
dev | http://localhost:8080/api/v1 | localhost:8080 |
qa | https://api-qa.estebanruano.com/api/v1 | api-qa.estebanruano.com:443 |
prod | https://api.estebanruano.com/api/v1 | api.estebanruano.com:443 |
Note: desktop/iOS/web
devpoints atlocalhost— different from Androiddev’s LAN IP. They are independent constants.
effectiveFlavor is always FLAVOR (not gated by IS_RELEASE), so you can debug-build any environment locally — isRelease = false only changes the app-name suffix ((DEBUG)) and enables the debug HTTP proxy toggle.
Commands
Desktop:
# Dev (default)
./gradlew :composeApp:run
# QA / prod
./gradlew :composeApp:run -Poter.flavor=qa
./gradlew :composeApp:run -Poter.flavor=prod -Poter.release=true
# Package native distribution
./gradlew :composeApp:packageReleaseDistributionForCurrentOS -Poter.flavor=prod -Poter.release=trueiOS framework:
./gradlew :composeApp:iosSimulatorArm64Framework # dev
./gradlew :composeApp:iosSimulatorArm64Framework -Poter.flavor=prod -Poter.release=trueWeb (wasmJS):
./gradlew :composeApp:wasmJsBrowserDevelopmentRun # dev
./gradlew :composeApp:wasmJsBrowserDistribution -Poter.flavor=prod -Poter.release=trueSwitching environments without rebuilding everything
Changing oter.flavor invalidates the generated BuildConfig.kt, which triggers recompilation of the affected target’s *Main source set. There is no runtime override — choose the flavor at build time.
Server (server/)
The Ktor server has no Gradle flavors. Dev vs prod is selected by environment variables at runtime:
ENVIRONMENT(development|production, defaultproduction) — read bylogback.xmlfor log format/level.LOG_LEVEL—DEBUGin dev, typicallyINFO/WARNin prod.JAVA_TOOL_OPTIONS=-Dio.ktor.development=true— enables Ktor dev mode.
See docker-compose.dev.yml for the canonical dev wiring and docs/infra/gcp-server-cloud-run.md for prod deploy.
Quick reference
| I want to… | Command |
|---|---|
| Run Android dev build | ./gradlew :androidApp:installDevDebug |
| Build prod APK/AAB | ./gradlew :androidApp:assembleProdRelease / :bundleProdRelease |
| Run desktop against local server | ./gradlew :composeApp:run |
| Run desktop against prod API | ./gradlew :composeApp:run -Poter.flavor=prod -Poter.release=true |
| Run web (wasmJS) dev | ./gradlew :composeApp:wasmJsBrowserDevelopmentRun |
| Run Ktor server (dev) | ENVIRONMENT=development LOG_LEVEL=DEBUG ./gradlew :server:run |
| Build server prod JAR | ./gradlew :server:shadowJar → java -jar server/build/libs/server-all.jar |
See also: root README — Building and running, INCLUDE_ANDROID Gradle flag.