Um Build Variant no desenvolvimento Android é uma combinação de um build type e um product flavor que determina como um APK ou AAB será compilado: com quais parâmetros, recursos e código. Cada variante de compilação representa uma configuração separada do Gradle com seu próprio applicationId, chaves de assinatura e dependências incluídas. De acordo com Google Android Developers, 2025, a configuração adequada de Build Variants reduz o tempo de compilação em até 40% ao excluir recursos desnecessários para cada variante. O sistema de variantes de compilação é a base do gerenciamento de configuração em projetos Android modernos.
Pontos Principais
Build Variant é o resultado da combinação de um Build Type e um Product Flavor. Se nenhum Product Flavor for definido no projeto, o Build Variant corresponde ao Build Type. O Gradle gera automaticamente o conjunto completo de variantes como o produto cartesiano de todos os FlavorDimensions, Product Flavors e Build Types. Por exemplo, para os flavors free/paid e os tipos debug/release, serão criadas 4 variantes: freeDebug, freeRelease, paidDebug, paidRelease.
Cada Build Variant recebe seu próprio nome no formato <Flavor><Type> com o flavor em maiúsculo. O Gradle gera tarefas separadas para esta variante: assembleFreeDebug, installFreeDebug, bundleFreeRelease. No Android Studio, a alternância entre variantes está disponível através do painel Build Variants (View → Tool Windows → Build Variants). A seleção de uma variante afeta qual código é compilado, quais recursos são incluídos e qual APK/AAB é produzido.
O sistema de Build Variants resolve três tarefas principais: separar configurações para diferentes ambientes (dev/staging/production), criar múltiplas versões de um app (free/paid) e testar A/B de compilações. Sem Build Variants, os desenvolvedores teriam que alternar manualmente flags e configurações, levando a erros de fator humano. De acordo com um estudo da Gradle Inc., 2024, a implementação de Build Variants reduz erros de compilação em 60% em projetos com três ou mais ambientes de implantação.
AGP (Android Gradle Plugin) calcula todas as combinações na fase de configuração. Se um projeto tem duas dimensões com dois e três flavors respectivamente, o Gradle criará 2 × 2 × 3 = 12 combinações, multiplicadas pelo número de Build Types (geralmente 2). Cada combinação recebe um nome único e um conjunto de tarefas. O AGP adiciona automaticamente um source set para cada variante: src/freeDebug/, src/paidRelease/, bem como os generalizados src/free/ e src/debug/. Prioridade de leitura de recursos: variant → flavor → type → main.
// Exemplo: 4 Build Variants
// flavorDimensions "version", "server"
// version: demo, prod
// server: mock, live
// buildTypes: debug, release
// Total: 2 × 2 × 2 = 8 variantes
android {
flavorDimensions "version", "server"
productFlavors {
demo { dimension "version" }
prod { dimension "version" }
mock { dimension "server" }
live { dimension "server" }
}
}
Build Type define como compilar o aplicativo — com ou sem informações de depuração, com ou sem otimização, com qual assinatura. Product Flavor define o que compilar — qual versão do produto. Build Type é um mecanismo de compilação (debug, release, staging). Product Flavor é uma variante de produto (free, paid, enterprise, demo). Ambos os conceitos são ortogonais: qualquer Build Type pode ser aplicado a qualquer Product Flavor.
Os Build Types padrão incluem debug (debuggable=true, minification=false, signing=debug.keystore) e release (debuggable=false, minification=true, signing=production.keystore). O Product Flavor padrão é um, sem nome (efetivamente o source set main). Os desenvolvedores podem adicionar seus próprios Build Types (por exemplo, “staging” com debuggable=true e minification=true) e qualquer número de Product Flavors. Outra diferença é que Build Types não podem ser agrupados em dimensões, mas Product Flavors podem.
A diferença prática principal: defaultConfig no build.gradle se aplica a todos os Variants, mas pode ser sobrescrito em productFlavors e buildTypes. Um BuildConfigField adicionado a um buildType é visível em todos os flavors desse tipo, enquanto um adicionado a um productFlavor é visível em todos os tipos desse flavor. Se um campo for definido em ambos, o buildType tem prioridade (ele é aplicado por último na cadeia).
| Característica | Build Type | Product Flavor |
|---|---|---|
| Propósito | Como compilar | O que compilar |
| Exemplos | debug, release, staging | free, paid, demo, enterprise |
| Padrão | debug + release | um (main) |
| Source Set | src/debug/, src/release/ | src/free/, src/paid/ |
| Dimensões | não | flavorDimensions |
| Ordem de aplicação | após flavor, sobrescreve | após defaultConfig |
| BuildConfigField | sobrescreve flavor | sobrescreve defaultConfig |
A configuração de Build Variants é feita no bloco android do arquivo build.gradle no nível do módulo. Primeiro, os buildTypes são declarados com seus parâmetros, depois flavorDimensions e productFlavors. O Gradle cria automaticamente as variantes com base nessas declarações. Cada variante herda o defaultConfig do módulo, sobrescrevendo os campos especificados. A ordem de declaração afeta a prioridade: os buildTypes são aplicados após os productFlavors.
Para acessar um Build Variant específico em scripts do Gradle, use android.applicationVariants (para módulos app) ou android.libraryVariants (para módulos de biblioteca). Esta é uma coleção que pode ser iterada para modificar a configuração de cada variante em tempo de configuração. Por exemplo, você pode adicionar programaticamente buildConfigField para todas as variantes que contenham a palavra “demo”.
O Android Gradle Plugin 8.x adicionou suporte para onVariants — uma API mais limpa para configurar variantes via lambdas. A API antiga (variantOutput, variantFilter) está marcada como obsoleta. Recomenda-se usar onVariants junto com onEach para módulos de biblioteca. Migrar de variantOutput para onVariants é uma etapa recomendada ao atualizar o AGP de 7.x para 8.x.
android {
buildTypes {
debug {
debuggable true
minification false
signingConfig signingConfigs.debug
}
release {
debuggable false
minification true
proguardFiles "proguard-rules.pro"
signingConfig signingConfigs.release
}
staging {
debuggable true
minification true
versionNameSuffix "-staging"
}
}
flavorDimensions "tier", "region"
productFlavors {
free { dimension "tier" }
paid { dimension "tier" }
us { dimension "region" }
eu { dimension "region" }
}
}
android.onVariants { variant ->
if (variant.name.contains("Demo")) {
variant.setEnabled(false)
}
}
Cada Build Variant recebe sua própria hierarquia de source sets — diretórios com código fonte, recursos e manifesto. Um source set está localizado em src/<variantName>/ (por exemplo, src/freeDebug/) e pode conter java/, res/, AndroidManifest.xml, assets/. Se um arquivo existir no source set da variante, ele sobrescreve o arquivo com o mesmo nome do source set principal (src/main/). Para recursos, ocorre uma mesclagem em vez de substituição — o sistema mescla recursos de todos os source sets ativos, dando prioridade aos específicos da variante.
Os source sets para um Build Variant são construídos em cadeia: src/main/ → src/flavor/ → src/type/ → src/flavorType/. Por exemplo, para paidRelease, main é aplicado primeiro, depois paid, depois release, depois paidRelease. Cada source set subsequente sobrescreve o anterior. Isso significa que src/release/res/values/strings.xml sobrescreverá as mesmas strings de src/paid/, mas src/paidRelease/res/ tem prioridade ainda maior.
Usar source sets para variantes é a maneira recomendada de personalizar recursos. Em vez de verificar BuildConfig.FLAVOR no código e ramificar a lógica, você pode simplesmente colocar arquivos diferentes em source sets diferentes. Por exemplo, ícones para as versões free e paid vão em src/free/res/ e src/paid/res/ respectivamente, e o AndroidManifest com diferentes permissões vai em src/free/AndroidManifest.xml e src/paid/AndroidManifest.xml. Isso é mais limpo, mais rápido (os recursos são compilados, não verificados em tempo de execução) e mais seguro (você não pode incluir acidentalmente funcionalidade paga na versão gratuita devido a um bug no código).
Em projetos multimódulo, cada módulo (biblioteca) pode ter seus próprios Build Variants. O AGP sincroniza automaticamente as variantes: se o módulo app compila paidRelease, todas as bibliotecas dependentes também são compiladas em suas variantes correspondentes a paidRelease. Surge um problema quando uma biblioteca não tem product flavors, mas o módulo app tem — então a biblioteca é compilada uma vez (release ou debug dependendo do tipo).
Para módulos de biblioteca, o Build Variant por padrão corresponde ao Build Type do módulo app, já que as bibliotecas não têm product flavors. Se uma biblioteca precisar se adaptar ao flavor do módulo app, os mesmos flavorDimensions e productFlavors devem ser declarados na biblioteca. O AGP corresponde flavors por correspondência exata de nome. O Gradle recomenda sincronizar flavors através da configuração de compilação no projeto raiz usando subprojects ou Convention Plugins.
A partir do AGP 8.1, as bibliotecas podem publicar múltiplas variantes — publicar todas as variantes da biblioteca em um repositório maven simultaneamente. Isso resolve o problema quando o módulo app usa um flavor pago, mas a biblioteca só está publicada para free. A publicação de múltiplas variantes (MVP) permite que o projeto dependente selecione a variante necessária automaticamente. Para habilitar o MVP, adicione publishing { multipleVariants { ... } } ao build.gradle da biblioteca.
Às vezes é necessário desativar alguns Build Variants — por exemplo, se a combinação mockRelease não fizer sentido (o servidor mock não deve ir para produção). O Gradle fornece variantFilter — um bloco DSL onde você pode verificar as propriedades de cada variante e desativá-la através de setIgnore(true). O VariantFilter é aplicado na fase de configuração, antes da criação de tarefas, portanto, uma variante desativada não gera tarefas assemble e install.
A filtragem também é útil para acelerar as compilações. Se um projeto tem 8 variantes, mas um desenvolvedor está trabalhando em apenas uma, as 7 variantes restantes ainda passam pela configuração. Ao usar variantFilter, as variantes desativadas não criam tarefas, reduzindo o tempo de configuração em 30-50% para projetos com 6+ dimensões de flavor. Em CI/CD, você pode filtrar dinamicamente as variantes através de parâmetros de linha de comando -PbuildOnly=paidRelease.
android {
variantFilter { variant ->
// Desativar mock para release e demo para production
def names = variant.flavors*.name
def isMock = names.contains("mock")
def isDemo = names.contains("demo")
def isRelease = variant.buildType.name == "release"
if ((isMock && isRelease) || (isDemo && !isMock)) {
variant.setIgnore(true)
}
}
}
// Filtragem dinâmica via parâmetros
if (project.hasProperty("buildOnly")) {
def target = project.property("buildOnly")
android.variantFilter { variant ->
variant.setIgnore(variant.name != target)
}
}
Perguntas Frequentes
Não há limite, mas o Gradle cria o produto cartesiano de todos os flavors e tipos. Se você tem 3 dimensões com 3 flavors cada e 3 build types, obtém 27 variantes. Muitas variantes diminuem a configuração. Recomenda-se não ter mais de 10–12 variantes em um módulo.
flavorDimensions agrupam Product Flavors em eixos independentes. Por exemplo, a dimensão “tier” (free, paid) e a dimensão “region” (us, eu). Sem dimensões, todos os flavors pertencem a um eixo, e o Gradle selecionará apenas um flavor de todos (você não pode ter free+us e paid+eu como variantes separadas).
No bloco productFlavor ou buildType, especifique applicationId. Por exemplo, para a versão free: free { applicationId “com.example.app.free” }. No manifesto, use ${applicationId} — o Gradle substituirá automaticamente o valor. Isso permite instalar ambas as variantes em um dispositivo.
No iOS, o equivalente de Build Variants é a combinação de Scheme + Configuration. Os Xcode Schemes são configurados através das configurações Debug/Release com diferentes parâmetros. Para várias versões (free/paid), são usadas Build Configurations e Preprocessor Macros. No Android, o conceito é mais formalizado e incorporado ao Gradle.
Sim, cada variante pode ter um tamanho de APK diferente. As compilações debug incluem informações de depuração, SDK e recursos não suportados. As compilações release com minification e resource shrinking produzem o tamanho mínimo. O Product Flavor também afeta o tamanho: uma versão free sem bibliotecas pagas será menor que a versão paid pelo tamanho dessas bibliotecas.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também