El problema real
En casi todos los equipos aparece el mismo momento: necesitás una build que apunte a otro backend, una app con branding distinto, una variante interna para QA o una versión demo que no sea exactamente igual a producción. Ahí aparecen los build types y los product flavors.
El problema es que muchas veces se usan como si fueran piezas intercambiables. Se mezcla entorno, nivel de logging, branding, distribución interna y comportamiento de negocio en el mismo mecanismo. El resultado es un build que “funciona”, pero que nadie puede explicar de forma simple.
Qué son los build types
Los build types representan formas técnicas de construir la misma app. Los dos clásicos son debug y release. Normalmente modelan diferencias como minificación, debuggability, suffixes, signing o logs.
buildTypes {
getByName("debug") {
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
isDebuggable = true
}
getByName("release") {
isMinifyEnabled = true
isShrinkResources = true
isDebuggable = false
}
}
La idea central es que siguen siendo la misma app, pero empaquetada de distinta manera según el contexto técnico.
Qué son los product flavors
Los flavors representan variantes funcionales o de negocio. Por ejemplo: dev y prod, free y paid, brandA y brandB, o distintos países si el producto realmente cambia por mercado.
flavorDimensions += "env"
productFlavors {
create("dev") {
dimension = "env"
buildConfigField("String", "BASE_URL", '"https://dev.api.com"')
}
create("prod") {
dimension = "env"
buildConfigField("String", "BASE_URL", '"https://api.com"')
}
}
Punto claveLos build types responden mejor a diferencias técnicas de empaquetado. Los flavors responden mejor a diferencias de entorno, negocio o producto.
La diferencia importante
Esta es la distinción que evita la mayoría de los desastres:
- Build type: cómo compilo o empaqueto.
- Flavor: qué variante del producto estoy construyendo.
Si querés logs extra, debuggability o minificación distinta, probablemente es build type. Si querés otra URL base, otra marca o capacidades distintas de producto, probablemente es flavor.
No siempre la frontera es perfecta, pero pensar así evita modelar todo con el mismo martillo.
Ejemplo concreto
Imaginá que tenés una app con dos entornos: staging y prod. Además querés las variantes clásicas debug y release. Entonces el build genera cuatro combinaciones:
stagingDebugstagingReleaseprodDebugprodRelease
Eso ya puede ser razonable. El problema empieza cuando sumás otro flavor de branding, otro de mercado y otro de distribución. La cantidad de variantes crece muy rápido, y con ella crecen tiempos de configuración, posibilidades de error y complejidad mental.
La explosión de variantes
Este es el costo que muchos equipos descubren tarde. Cada dimensión nueva multiplica combinaciones. No es solo más trabajo para Gradle; también es más trabajo para CI, QA, documentación, signing, testing y soporte.
AtenciónNo toda diferencia necesita transformarse en flavor. Muchas cosas pueden resolverse mejor con configuración remota, feature flags o decisiones runtime.
Si una variación no necesita cambiar recursos, manifest, código fuente específico o identidad del paquete, a veces no conviene modelarla como flavor. Meter demasiadas variantes en el build vuelve más frágil algo que podría ser más simple.
Reglas prácticas para no sufrir
- Usá
debugyreleasecomo base, salvo que tengas una razón muy concreta para agregar más build types. - Creá flavors solo cuando la diferencia sea realmente de producto, entorno o distribución.
- Evitá usar flavors para compensar malas decisiones de arquitectura.
- No multipliques dimensiones si el equipo no va a poder sostener esa complejidad.
- Antes de crear una variante nueva, preguntate si el problema podría resolverse en runtime.
android {
flavorDimensions += "env"
productFlavors {
create("staging") { dimension = "env" }
create("prod") { dimension = "env" }
}
}
La mejor configuración no es la más sofisticada. Es la que representa lo necesario sin crear un sistema paralelo imposible de mantener.
Cierre
Los build types y los product flavors son herramientas potentes cuando reflejan decisiones claras. El problema no es que existan muchas variantes; el problema es modelarlas sin criterio. Si distinguís bien entre diferencias técnicas y diferencias de producto, ya evitás buena parte del caos que suele aparecer en builds Android complejos.