Skip to main content

Build variants, environments, and secrets

A build type describes how software is built (debug, release). A product flavor represents a product/environment dimension (demo, paid; sometimes staging, production). Their cross-product creates variants, so dimensions must be intentional.

android {
buildTypes {
release { isMinifyEnabled = true }
debug { applicationIdSuffix = ".debug" }
}
flavorDimensions += "environment"
productFlavors {
create("staging") {
dimension = "environment"
applicationIdSuffix = ".staging"
}
create("production") { dimension = "environment" }
}
}

Different application IDs let staging and production coexist. They also imply different OAuth redirect URIs, App Links, Firebase apps, API credentials, content providers, and signing fingerprints—test those contracts.

Secrets​

Anything shipped in an APK/AAB is recoverable: BuildConfig, resources, native code, and downloaded config are not secret stores. Public client API identifiers may be shipped but must be restricted by package/certificate and server policy. Private signing keys, service-account credentials, and backend secrets belong in protected CI/server stores.

Inject signing material only into the release job, mask logs, avoid command-line echo, restrict environment approvals, rotate credentials, and never commit a keystore/password file.

Variant control​

Variant explosion increases compile/test/release cost. Disable unsupported combinations with the Android Components API and document the supported matrix. Ensure production cannot accidentally point to staging or enable debug diagnostics.

Practical mistakes​

  • ❌ Treat a staging base URL as the only environment difference.
  • ✅ Verify identity, signing, links, analytics, push, billing, and backend policy.
  • ❌ Put a “secret” string in BuildConfig.
  • ✅ Move trusted secrets server-side.
  • ❌ Test only debug while publishing shrunk release.
  • ✅ Add release smoke/contract tests.

Source​