Esta página usa as informações fornecidas na Visão geral da configuração do seu build para mostrar como configurar variantes de build para criar diferentes versões do app em um só projeto e como gerenciar corretamente as dependências e configurações de assinatura.
Cada variante de build representa uma versão diferente do seu app que pode ser criada. Por exemplo: você pode querer criar duas versões do app, uma com conteúdo limitado e sem custos financeiros e outra com mais conteúdo e paga. Você também pode criar builds do app que sejam direcionados a diferentes dispositivos, com base no nível da API ou em outras variações.
Variantes de build são o resultado do uso de um conjunto específico de regras pelo Gradle para combinar configurações, código e recursos nos seus tipos de build e variações de produtos. Apesar de as variantes de build não serem configuradas diretamente, é necessário configurar os tipos de build e as variações de produto que compõem as variantes.
Por exemplo, uma variação de produto "demo" (demonstração) pode especificar diferentes recursos e
requisitos de dispositivo, como código-fonte, recursos e níveis
mínimos da API personalizados. Já um tipo de build "debug" (depuração) aplica diferentes configurações de empacotamento e
de build, como opções de depuração e chaves de assinatura. A variante
de build resultante é a versão "demoDebug" do seu app, contendo uma
combinação das configurações e dos recursos incluídos na variação
de produto “demo”, no tipo de build "debug" e no conjunto de origem main/
.
Configurar tipos de build
Você pode criar e configurar tipos de build no arquivo build.gradle
do módulo dentro do bloco android
. Quando você cria um novo módulo, o Android Studio cria automaticamente os tipos de build de depuração e de lançamento. Embora o tipo de build de depuração não apareça no
arquivo de configuração do build, o Android Studio o configura com
debuggable true
. Isso permite depurar o app em dispositivos
Android seguros e configura a assinatura de apps com um keystore de depuração genérico.
É possível adicionar o tipo de build de depuração às suas configurações caso você queira adicionar
ou mudar alguma configuração. O exemplo a seguir especifica um
applicationIdSuffix
para o tipo de build de depuração e configura
um tipo de build "staging" (de preparo), que é inicializado usando as configurações do tipo de build de depuração.
Groovy
android { defaultConfig { manifestPlaceholders = [hostName:"www.example.com"] ... } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { applicationIdSuffix ".debug" debuggable true } /** * The `initWith` property allows you to copy configurations from other build types, * then configure only the settings you want to change. This one copies the debug build * type, and then changes the manifest placeholder and application ID. */ staging { initWith debug manifestPlaceholders = [hostName:"internal.example.com"] applicationIdSuffix ".debugStaging" } } }
Kotlin
android { defaultConfig { manifestPlaceholders["hostName"] = "www.example.com" ... } buildTypes { getByName("release") { isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") } getByName("debug") { applicationIdSuffix = ".debug" isDebuggable = true } /** * The `initWith` property allows you to copy configurations from other build types, * then configure only the settings you want to change. This one copies the debug build * type, and then changes the manifest placeholder and application ID. */ create("staging") { initWith(getByName("debug")) manifestPlaceholders["hostName"] = "internal.example.com" applicationIdSuffix = ".debugStaging" } } }
Observação: ao fazer mudanças em um arquivo de configuração do build,
o Android Studio exige a sincronização do projeto com a nova
configuração. Para isso, clique em Sync Now na barra de notificações que aparece a cada mudança ou em Sync Project na barra de ferramentas. Se o Android
Studio perceber erros na sua configuração, a
janela Messages vai aparecer para mostrar o problema.
Para saber mais sobre todas as propriedades que podem ser configuradas com tipos de build, leia a referência de DSL para tipos de build.
Configurar variações de produtos
A criação de variações de produtos é semelhante à de tipos de build: basta adicioná-las ao
bloco productFlavors
na configuração do build e aplicar as definições que você quiser.
As variações de produtos são compatíveis com as mesmas propriedades que
defaultConfig
. Isso porque defaultConfig
pertence à classe
ProductFlavor
. Isso significa que você pode fornecer a configuração
básica para todas as variações do bloco defaultConfig
, e
cada uma delas pode modificar esses valores padrão, como o applicationId
. Para
saber mais sobre o ID do aplicativo, leia
Definir o ID do aplicativo.
Observação: ainda é necessário especificar um nome de pacote usando o
atributo package
no arquivo de manifesto main/
. Você também precisa usar esse nome de pacote no código-fonte para se referir à classe R ou para resolver qualquer atividade relativa ou registro de serviço. Isso permite usar o applicationId
para fornecer a cada variação de produto um código exclusivo de empacotamento e distribuição sem precisar mudar o código-fonte.
Todas as variações precisam pertencer a uma dimensão nomeada, que é um grupo de variações de produtos. Atribua todas as variações a uma dimensão; caso contrário, você receberá o erro de compilação mostrado abaixo. Se determinado módulo especificar apenas uma dimensão de variações, o Plug-in do Android para Gradle atribuirá automaticamente todas as variações do módulo a essa dimensão.
Error:All flavors must now belong to a named flavor dimension. The flavor 'flavor_name' is not assigned to a flavor dimension.
A amostra de código a seguir cria uma dimensão de variações chamada "versão" e adiciona
variações de produto "demo" (demonstração) e "full" (completa). Essas variações fornecem os próprios
applicationIdSuffix
e
versionNameSuffix
:
Groovy
android { ... defaultConfig {...} buildTypes { debug{...} release{...} } // Specifies one flavor dimension. flavorDimensions "version" productFlavors { demo { // Assigns this product flavor to the "version" flavor dimension. // If you are using only one dimension, this property is optional, // and the plugin automatically assigns all the module's flavors to // that dimension. dimension "version" applicationIdSuffix ".demo" versionNameSuffix "-demo" } full { dimension "version" applicationIdSuffix ".full" versionNameSuffix "-full" } } }
Kotlin
android { ... defaultConfig {...} buildTypes { getByName("debug"){...} getByName("release"){...} } // Specifies one flavor dimension. flavorDimensions += "version" productFlavors { create("demo") { // Assigns this product flavor to the "version" flavor dimension. // If you are using only one dimension, this property is optional, // and the plugin automatically assigns all the module's flavors to // that dimension. dimension = "version" applicationIdSuffix = ".demo" versionNameSuffix = "-demo" } create("full") { dimension = "version" applicationIdSuffix = ".full" versionNameSuffix = "-full" } } }
Observação: para apps legados que são distribuídos usando APKs no Google Play (criados antes de
agosto de 2021), para distribuí-los usando o suporte para vários
APKs no Google Play, atribua o mesmo valor applicationId
a todas as variantes e dê um
versionCode
diferente a cada uma. Para distribuir diferentes
variantes do seu app separadamente no Google Play, você precisa atribuir um
applicationId
diferente a cada uma delas.
Depois de criar e configurar suas variações de produtos, clique em Sync Now na barra de notificações. Quando a sincronização for concluída, o Gradle criará as variantes de compilação automaticamente com base nos tipos de build e nas variações de produto e nomeará as variantes de acordo com <product-flavor><Build-Type>
. Por exemplo, se você criou as variações de produto "demo" e "full" e manteve os tipos de build padrão "debug" (depuração) e "release" (lançamento), o Gradle criará as seguintes variantes de build:
- demoDebug
- demoRelease
- fullDebug
- fullRelease
É possível mudar a variante de build para aquela que você quer criar e executar. Para fazer isso, basta acessar Build > Select Build Variant e selecionar uma opção no menu suspenso. Para começar a personalizar cada variante de build com os próprios recursos, você precisará saber como criar e gerenciar conjuntos de origem.
Alterar o ID do aplicativo para variantes de build
Ao criar um APK ou AAB para o app, as ferramentas de build marcam o app com o ID do aplicativo definido no blocodefaultConfig
do arquivo build.gradle
,
como mostrado abaixo. No entanto, se você quiser criar versões diferentes do app
para aparecerem como listagens separadas na Google Play Store, como uma versão "free" (sem custo financeiro) e uma "pro" (avançada), será necessário criar
variantes de build
separadas, cada uma com um ID de aplicativo
diferente.
Nesse caso, cada variante de build precisa ser definida como uma variação de produto
diferente. Para cada variação
dentro do bloco productFlavors
, é possível redefinir a propriedade applicationId
ou anexar um segmento ao ID do aplicativo padrão
usando applicationIdSuffix
, como mostrado abaixo:
Groovy
android { defaultConfig { applicationId "com.example.myapp" } productFlavors { free { applicationIdSuffix ".free" } pro { applicationIdSuffix ".pro" } } }
Kotlin
android { defaultConfig { applicationId = "com.example.myapp" } productFlavors { create("free") { applicationIdSuffix = ".free" } create("pro") { applicationIdSuffix = ".pro" } } }
applicationIdSuffix
para anexar um segmento de acordo com o
tipo de build da seguinte forma:
Groovy
android { ... buildTypes { debug { applicationIdSuffix ".debug" } } }
Kotlin
android { ... buildTypes { getByName("debug") { applicationIdSuffix = ".debug" } } }
versionCode
diferente. Para mais
informações, leia sobre
Suporte a vários APKs. A publicação
com AABs não é afetada, porque usa um único artefato com um único
código de versão e ID do aplicativo por padrão.
Cuidado: para compatibilidade com Ferramentas do SDK anteriores, se
você não definir a propriedade applicationId
no
arquivo build.gradle
, as ferramentas de build vão usar o nome do pacote do
arquivo AndroidManifest.xml
como o ID do aplicativo. Nesse caso,
a refatoração do nome de pacote também muda o ID do aplicativo.
Dica: se você precisar fazer referência ao ID do aplicativo no
arquivo de manifesto, use o marcador ${applicationId}
em qualquer
atributo do manifesto. Durante uma compilação, o Gradle substitui essa tag pelo
ID do aplicativo. Para saber mais, acesse Injetar variáveis de build no
manifesto.
Combinar diversas variações de produtos com dimensões de variação
Em alguns casos, é recomendável combinar as configurações de diferentes variações de produto. Por exemplo, recomendamos criar configurações diferentes para as variações de produto "full" e "demo", de acordo com o nível da API. Para fazer isso, o plug-in do Android para Gradle permite criar vários grupos de variações de produtos, chamados de dimensão de variações. Ao criar o app, para criar a variante de compilação final, o Gradle combina a configuração de uma variação de produto de cada dimensão de variações definida a uma configuração de um tipo de build. O Gradle não combina variações de produto que pertençam à mesma dimensão.
O exemplo de código a seguir usa a propriedade
flavorDimensions
para criar uma dimensão
de variações "mode" (modo) para agrupar as variações de produto "full" (completa) e "demo" (demonstração) e uma dimensão
"api" para agrupar as configurações das variações de produto, de acordo com o nível da API:
Groovy
android { ... buildTypes { debug {...} release {...} } // Specifies the flavor dimensions you want to use. The order in which you // list each dimension determines its priority, from highest to lowest, // when Gradle merges variant sources and configurations. You must assign // each product flavor you configure to one of the flavor dimensions. flavorDimensions "api", "mode" productFlavors { demo { // Assigns this product flavor to the "mode" flavor dimension. dimension "mode" ... } full { dimension "mode" ... } // Configurations in the "api" product flavors override those in "mode" // flavors and the defaultConfig block. Gradle determines the priority // between flavor dimensions based on the order in which they appear next // to the flavorDimensions property above--the first dimension has a higher // priority than the second, and so on. minApi24 { dimension "api" minSdkVersion 24 // To ensure the target device receives the version of the app with // the highest compatible API level, assign version codes in increasing // value with API level. To learn more about assigning version codes to // support app updates and uploading to Google Play, read Multiple APK Support versionCode 30000 + android.defaultConfig.versionCode versionNameSuffix "-minApi24" ... } minApi23 { dimension "api" minSdkVersion 23 versionCode 20000 + android.defaultConfig.versionCode versionNameSuffix "-minApi23" ... } minApi21 { dimension "api" minSdkVersion 21 versionCode 10000 + android.defaultConfig.versionCode versionNameSuffix "-minApi21" ... } } } ...
Kotlin
android { ... buildTypes { getByName("debug") {...} getByName("release") {...} } // Specifies the flavor dimensions you want to use. The order in which you // list each dimension determines its priority, from highest to lowest, // when Gradle merges variant sources and configurations. You must assign // each product flavor you configure to one of the flavor dimensions. flavorDimensions += listOf("api", "mode") productFlavors { create("demo") { // Assigns this product flavor to the "mode" flavor dimension. dimension = "mode" ... } create("full") { dimension = "mode" ... } // Configurations in the "api" product flavors override those in "mode" // flavors and the defaultConfig block. Gradle determines the priority // between flavor dimensions based on the order in which they appear next // to the flavorDimensions property above--the first dimension has a higher // priority than the second, and so on. create("minApi24") { dimension = "api" minSdk = 24 // To ensure the target device receives the version of the app with // the highest compatible API level, assign version codes in increasing // value with API level. To learn more about assigning version codes to // support app updates and uploading to Google Play, read Multiple APK Support versionCode = 30000 + (android.defaultConfig.versionCode ?: 0) versionNameSuffix = "-minApi24" ... } create("minApi23") { dimension = "api" minSdk = 23 versionCode = 20000 + (android.defaultConfig.versionCode ?: 0) versionNameSuffix = "-minApi23" ... } create("minApi21") { dimension = "api" minSdk = 21 versionCode = 10000 + (android.defaultConfig.versionCode ?: 0) versionNameSuffix = "-minApi21" ... } } } ...
O número de variantes de build que o Gradle cria é igual ao produto do número de variações presentes em cada dimensão de variações e do número de tipos de build que você configura. Quando o Gradle dá nome a cada variante de build ou artefato correspondente, as variações de produto que pertencem à dimensão de maior prioridade aparecem primeiro, seguidas das outras de menor prioridade e, por último, dos tipos de build. Usando a configuração do build acima como exemplo, o Gradle cria um total de 12 variantes de build com o seguinte esquema de nomenclatura:
- Variante de compilação:
[minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
- APK correspondente:
app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
- Por exemplo:
- Variante de build:
minApi24DemoDebug
- APK correspondente:
app-minApi24-demo-debug.apk
Além dos diretórios de conjunto de origem que você pode criar para cada
variante de build e variação de produto, também é possível criar diretórios de conjunto de origem
para cada combinação de variações de produto. Por exemplo, é possível criar e adicionar origens Java ao diretório src/demoMinApi24/java/
, e o Gradle usa essas origens só para compilar uma variante que combina duas dessas variações de produto. Os conjuntos de origem criados para combinações de variação de produto têm prioridade maior do que os que pertencem a cada variação de produto. Para saber mais sobre conjuntos de origem e como o Gradle
combina recursos, leia a seção sobre como Criar
conjuntos de origem.
Filtrar variantes
O Gradle cria uma variante de compilação para cada combinação possível das variações de produto e tipos de build que você configurar. No entanto, é possível que algumas variantes sejam desnecessárias ou não façam sentido no contexto do seu projeto. Você pode remover determinadas configurações de variante de build
criando um filtro de variantes no arquivo build.gradle
do
módulo.
Usando a configuração do build da seção anterior como exemplo,
suponha que você planeje oferecer compatibilidade somente com os níveis da API 23 e mais recentes para a versão de
demonstração do app. Você pode usar o bloco
variantFilter
para filtrar todas as configurações
de variantes de build que combinam as variações de produtos "minApi21" e "demo":
Groovy
android { ... buildTypes {...} flavorDimensions "api", "mode" productFlavors { demo {...} full {...} minApi24 {...} minApi23 {...} minApi21 {...} } variantFilter { variant -> def names = variant.flavors*.name // To check for a certain build type, use variant.buildType.name == "<buildType>" if (names.contains("minApi21") && names.contains("demo")) { // Gradle ignores any variants that satisfy the conditions above. setIgnore(true) } } } ...
Kotlin
android { ... buildTypes {...} flavorDimensions += listOf("api", "mode") productFlavors { create("demo") {...} create("full") {...} create("minApi24") {...} create("minApi23") {...} create("minApi21") {...} } } androidComponents { beforeVariants { variantBuilder -> // To check for a certain build type, use variantBuilder.buildType == "<buildType>" if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) { // Gradle ignores any variants that satisfy the conditions above. variantBuilder.enabled = false } } } ...
Depois de adicionar um filtro de variante à configuração do build e clicar em Sync
Now na barra de notificações, o Gradle ignorará todas as variantes de build que atenderem
às condições especificadas. Assim, elas não serão mais exibidas no menu suspenso
quando você clicar em Build > Select Build Variant na barra de menus
(ou Build Variants na
barra da janela de ferramentas).
Criar conjuntos de origem
Por padrão, o Android Studio criará o
conjunto de origem de main/
e diretórios para
tudo o que você quiser compartilhar entre suas variantes de build. No entanto, você
pode criar novos conjuntos de origem para determinar exatamente quais arquivos o Gradle precisa compilar e
empacotar para tipos de build, variações de produtos (e combinações de
variações de produtos ao usar dimensões
de variações) e variantes de build específicos. Por exemplo, é possível definir a funcionalidade básica do conjunto de origem main/
e usar os conjuntos de origem de uma variação de produto para mudar o aspecto visual do seu app para diferentes clientes. Além disso, é possível incluir permissões especiais e recursos de geração de registros somente para variantes de compilação que usam o tipo de build de depuração.
O Gradle espera que você organize os arquivos e diretórios dos conjuntos de origem de uma forma específica, semelhante ao conjunto de origem main/
. Por exemplo, o Gradle espera que os arquivos de classe Java específicos do seu tipo de build "debug" estejam no diretório src/debug/java/
.
O plug-in do Android para Gradle disponibiliza uma tarefa muito útil do Gradle, que mostra como organizar seus arquivos por tipo de build, variação de produto e variante de compilação. A amostra de saída da tarefa a seguir descreve onde o Gradle espera encontrar determinados arquivos para o tipo de compilação "debug":
------------------------------------------------------------ Project :app ------------------------------------------------------------ ... debug ---- Compile configuration: compile build.gradle name: android.sourceSets.debug Java sources: [app/src/debug/java] Manifest file: app/src/debug/AndroidManifest.xml Android resources: [app/src/debug/res] Assets: [app/src/debug/assets] AIDL sources: [app/src/debug/aidl] RenderScript sources: [app/src/debug/rs] JNI sources: [app/src/debug/jni] JNI libraries: [app/src/debug/jniLibs] Java-style resources: [app/src/debug/resources]
Para ver essa saída, faça o seguinte:
- Clique em Gradle no lado direito da janela do ambiente de desenvolvimento integrado.
- Vá até MyApplication > Tasks > android e clique duas vezes em sourceSets. Para ver a pasta Tasks, é necessário permitir que o Gradle crie a lista de tarefas durante a sincronização clicando em File > Settings > Experimental e desmarcando Do not build Gradle task list during Gradle sync (Android Studio > Preferences > Experimental no macOS). Depois que o Gradle executar a tarefa, a janela Run será aberta para exibir a saída.
- Caso a exibição não esteja no modo de texto mostrado acima, clique em Toggle view
no lado esquerdo da janela Run.
Observação: a saída da tarefa também mostra como organizar conjuntos de origem
para os arquivos que você quer usar para executar testes com o app, como os
conjuntos de origem de teste
test/
e androidTest/
.
Ao criar uma nova variante de build, o Android Studio não cria os diretórios de conjuntos de origem, mas oferece algumas opções que podem ajudar. Por exemplo, para criar apenas o diretório java/
para seu tipo de build "debug":
- Abra o painel Project e selecione a visualização Project no menu suspenso na parte superior do painel.
- Navegue para
MyProject/app/src/
. - Clique com o botão direito do mouse no diretório
src
e selecione New > Directory. - No menu em Gradle Source Sets, selecione full/java.
- Pressione Enter.
O Android Studio cria um diretório do conjunto de origem para o tipo de build de depuração e,
em seguida, cria o diretório java/
dentro dele. Uma alternativa é fazer com que o Android Studio crie diretórios quando você adicionar um novo arquivo no seu projeto para uma variante de compilação específica. Por exemplo, para criar um arquivo Values XML para o tipo de build "debug":
- No mesmo painel Project, clique com o botão direito do mouse no diretório
src
e selecione New > XML > Values XML File. - Insira o nome do arquivo XML ou mantenha o nome padrão.
- No menu suspenso ao lado de Target Source Set, selecione debug.
- Clique em Finish.
Como o tipo de build "debug" foi especificado como o conjunto de origem de destino, o Android Studio criará os diretórios necessários automaticamente ao criar o arquivo XML. A estrutura de diretórios resultante será semelhante à Figura 2.

Figura 2. Novos diretórios de conjuntos de origem para o tipo de build de depuração.
Com o mesmo procedimento, também é possível criar diretórios de conjuntos de origem para
variações de produtos, como src/demo/
, e para variantes de build, como src/demoDebug/
. Além disso, você pode criar conjuntos de origem para testes, voltados para variantes de build específicas, como em src/androidTestDemoDebug/
. Para saber mais, consulte
testes de conjuntos de origem.
Mudar as configurações do conjunto de origem padrão
Se você tem origens que não são organizadas na estrutura padrão de arquivos de conjunto
de origem que o Gradle espera, como descrito acima na seção sobre como
Criar conjuntos de origem, use o bloco
sourceSets
para mudar o local em que o Gradle procura
arquivos de cada componente de um conjunto de origem. O sourceSets
precisa estar
no bloco android
. Não é necessário realocar os
arquivos de origem, apenas fornecer ao Gradle os caminhos (em relação ao arquivo
build.gradle
no nível do módulo) em que ele
vai encontrar os arquivos de cada componente do conjunto de origem. Para saber quais componentes podem ser
configurados e se eles podem ser associados a diversos arquivos ou diretórios,
consulte a referência da API do Plug-in do Android para Gradle.
O exemplo de código a seguir mapeia origens do diretório app/other/
em determinados componentes do conjunto de origem main
e muda o
diretório raiz do conjunto de origem androidTest
.
Groovy
android { ... sourceSets { // Encapsulates configurations for the main source set. main { // Changes the directory for Java sources. The default directory is // 'src/main/java'. java.srcDirs = ['other/java'] // If you list multiple directories, Gradle uses all of them to collect // sources. Because Gradle gives these directories equal priority, if // you define the same resource in more than one directory, you get an // error when merging resources. The default directory is 'src/main/res'. res.srcDirs = ['other/res1', 'other/res2'] // Note: You should avoid specifying a directory which is a parent to one // or more other directories you specify. For example, avoid the following: // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings'] // You should specify either only the root 'other/res1' directory, or only the // nested 'other/res1/layouts' and 'other/res1/strings' directories. // For each source set, you can specify only one Android manifest. // By default, Android Studio creates a manifest for your main source // set in the src/main/ directory. manifest.srcFile 'other/AndroidManifest.xml' ... } // Create additional blocks to configure other source sets. androidTest { // If all the files for a source set are located under a single root // directory, you can specify that directory using the setRoot property. // When gathering sources for the source set, Gradle looks only in locations // relative to the root directory you specify. For example, after applying the // configuration below for the androidTest source set, Gradle looks for Java // sources only in the src/tests/java/ directory. setRoot 'src/tests' ... } } } ...
Kotlin
android { ... // Encapsulates configurations for the main source set. sourceSets.getByName("main") { // Changes the directory for Java sources. The default directory is // 'src/main/java'. java.setSrcDirs("other/java") // If you list multiple directories, Gradle uses all of them to collect // sources. Because Gradle gives these directories equal priority, if // you define the same resource in more than one directory, you get an // error when merging resources. The default directory is 'src/main/res'. res.setSrcDirs("other/res1", "other/res2") // Note: You should avoid specifying a directory which is a parent to one // or more other directories you specify. For example, avoid the following: // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings'] // You should specify either only the root 'other/res1' directory, or only the // nested 'other/res1/layouts' and 'other/res1/strings' directories. // For each source set, you can specify only one Android manifest. // By default, Android Studio creates a manifest for your main source // set in the src/main/ directory. manifest.srcFile("other/AndroidManifest.xml") ... } // Create additional blocks to configure other source sets. sourceSets.getByName("androidTest") { // If all the files for a source set are located under a single root // directory, you can specify that directory using the setRoot property. // When gathering sources for the source set, Gradle looks only in locations // relative to the root directory you specify. For example, after applying the // configuration below for the androidTest source set, Gradle looks for Java // sources only in the src/tests/java/ directory. setRoot("src/tests") ... } } ...
Observe que um diretório de origem só pode pertencer a um único conjunto de origem. Por exemplo, não é possível usar as
mesmas origens de teste para os conjuntos de origem test
e androidTest
. Isso
ocorre porque o Android Studio cria módulos do IntelliJ separados para cada conjunto de origem e não oferece suporte
a raízes de conteúdo duplicado nesses conjuntos.
Criar usando conjuntos de origem
Você pode usar os diretórios dos conjuntos de origem para armazenar o código e os recursos que quer empacotar apenas com determinadas configurações. Por exemplo, se você estiver criando a variante de compilação "demoDebug", que é o produto da combinação de uma variação de produto "demo" e um tipo de build "debug", o Gradle examinará esses diretórios e atribuirá as seguintes prioridades a eles:
-
src/demoDebug/
(conjunto de origem da variante de build) -
src/debug/
(conjunto de origem de tipo de build) -
src/demo/
(conjunto de origem de variação de produto) -
src/main/
(conjunto de origem principal)
Os conjuntos de origem criados para combinações de variação de produto precisam incluir todas as dimensões de variação. Por exemplo, o conjunto de origem da variante de build precisa ser a combinação do (tipo de build + todas as dimensões de variações). Não há suporte à mesclagem de códigos e recursos envolvendo pastas que abrangem várias, mas não todas, dimensões de variações.
Observação: se você combinar diversas variações
de produto, a prioridade entre elas será determinada pela dimensão
a que pertencem. Ao classificar as dimensões de variação com a
propriedade
android.flavorDimensions
, as variações de produto que
pertencem à primeira dimensão listada terão maior prioridade do que
as que pertencem à segunda dimensão e assim por diante. Além disso, os conjuntos de origem que você criar para combinações de variação de produto terão prioridade maior em relação aos conjuntos de origem que pertencem a cada variação de produto individualmente.
A ordem listada acima determina qual conjunto de origem tem maior prioridade quando o Gradle combina código e recursos. Como o diretório demoDebug/
do conjunto de origem provavelmente contém arquivos específicos dessa variante de compilação, caso demoDebug/
contenha um arquivo também definido em debug/
, o Gradle usará o arquivo do conjunto de origem de demoDebug/
. De forma semelhante, o Gradle atribui aos arquivos que se encontram nos conjuntos de origem de tipo de build e de variação de produto uma prioridade maior do que os mesmos arquivos presentes em main/
.
O Gradle considera essa ordem de prioridade ao aplicar as seguintes regras de compilação:
- Todo código-fonte dos diretórios
java/
é compilado junto para gerar uma única saída.Observação: para uma variante de build específica, o Gradle vai gerar um erro de build se encontrar dois ou mais diretórios de conjuntos de origem que tenham definido a mesma classe Java. Por exemplo, ao criar um app de depuração, não é possível definir
src/debug/Utility.java
esrc/main/Utility.java
juntos. Isso porque o Gradle examina os dois diretórios durante o processo de compilação e gera um erro "duplicate class" (classe duplicada). Caso você queira ter diferentes versões doUtility.java
para diferentes tipos de build, é possível fazer com que cada tipo de build defina a própria versão do arquivo e não a inclua no conjunto de origemmain/
. - Os manifestos são combinados em um único manifesto. A prioridade é atribuída na mesma ordem da lista acima. Ou seja, as configurações de manifesto para um tipo de build modificam as configurações de manifesto para uma variação de produto e assim por diante. Para saber mais, leia sobre a combinação de manifestos.
- De forma semelhante, os arquivos dos diretórios
values/
são combinados. Caso dois arquivos tenham o mesmo nome, comostrings.xml
, a prioridade será concedida na mesma ordem da lista acima. Ou seja, os valores definidos em um arquivo no conjunto de origem do tipo de build substituem os valores definidos no mesmo arquivo em uma variação de produto e assim por diante. - Os recursos dos diretórios
res/
easset/
são empacotados juntos. Se houver recursos com o mesmo nome definidos em dois ou mais conjuntos de origem, a prioridade será concedida na ordem da lista acima. - Por fim, o Gradle atribui a menor prioridade aos recursos e manifestos incluídos com dependências de módulo de biblioteca quando o app é criado.
Declarar dependências
Você pode configurar uma dependência para uma variante de build específica ou
um conjunto de origem de teste específico usando
o nome da variante ou do conjunto como prefixo antes da
palavra-chave Implementation
, como mostrado no exemplo a seguir.
Groovy
dependencies { // Adds the local "mylibrary" module as a dependency to the "free" flavor. freeImplementation project(":mylibrary") // Adds a remote binary dependency only for local tests. testImplementation 'junit:junit:4.12' // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' }
Kotlin
dependencies { // Adds the local "mylibrary" module as a dependency to the "free" flavor. freeImplementation(project(":mylibrary")) // Adds a remote binary dependency only for local tests. testImplementation("junit:junit:4.12") // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation("com.android.support.test.espresso:espresso-core:3.0.2") }
Para saber mais, consulte Adicionar dependências de build.
Usar o gerenciamento de dependências com reconhecimento de variantes
O plug-in do Android 3.0.0 e mais recentes inclui um novo mecanismo de dependência que faz a correspondência automática
de variantes ao consumir uma biblioteca. Isso significa que a variante debug
de um app consome
automaticamente a variante debug
de uma biblioteca e assim por diante. Isso também funciona ao usar variações: a
variante freeDebug
de um app consumirá a variante freeDebug
de uma biblioteca.
Para que o plug-in estabeleça correspondências precisas entre as variantes, será necessário fornecer substitutos de correspondência aos casos em que uma correspondência direta é impossível. Verifique se o app configura um tipo de build chamado "staging" (de preparo), mas uma das dependências de biblioteca dele não. Quando o plug-in tentar criar a versão "staging" do app, ele não saberá qual versão da biblioteca usar, e você verá uma mensagem de erro semelhante a esta:
Error:Failed to resolve: Could not resolve project :mylibrary. Required by: project :app
Resolver erros de build relacionados à correspondência de variantes
O plug-in inclui elementos DSL para ajudar a controlar como o Gradle solucionará situações em que uma correspondência direta de variante entre um app e uma dependência não é possível. Consulte a tabela para determinar qual propriedade de DSL você precisa usar a fim de solucionar certos erros de compilação relacionados à correspondência de dependências com reconhecimento de variantes.
Causa do erro de compilação | Resolução |
---|---|
Por exemplo, o app inclui um tipo de build "staging" (de preparo), mas uma dependência inclui somente os tipos de build "debug" (depuração) e "release" (lançamento). Observe que não há problema quando uma dependência de biblioteca inclui um tipo de build que o app não tem. Isso ocorre porque o plug-in simplesmente nunca solicita esse tipo de build da dependência. |
Use o elemento Groovy// In the app's build.gradle file. android { buildTypes { debug {} release {} staging { // Specifies a sorted list of fallback build types that the // plugin should try to use when a dependency does not include a // "staging" build type. You may specify as many fallbacks as you // like, and the plugin selects the first build type that's // available in the dependency. matchingFallbacks = ['debug', 'qa', 'release'] } } } Kotlin// In the app's build.gradle file. android { buildTypes { getByName("debug") {} getByName("release") {} create("staging") { // Specifies a sorted list of fallback build types that the // plugin should try to use when a dependency does not include a // "staging" build type. You may specify as many fallbacks as you // like, and the plugin selects the first build type that's // available in the dependency. matchingFallbacks += listOf("debug", "qa", "release") } } } |
Para determinada dimensão de variações que existe no app e na dependência de biblioteca, o app inclui variações que a biblioteca não tem. Por exemplo, tanto o app quanto as dependências de biblioteca incluem uma dimensão de variação "tier" (nível). Entretanto, a dimensão "tier" no app inclui variações "free" (sem custo financeiro) e "paid" (paga), mas uma dependência inclui somente variações "demo" (demonstração) e "paid" (paga) para a mesma dimensão. Observe que, para determinada dimensão de variação que existe no app e nas dependências de biblioteca, não há problema quando uma biblioteca inclui uma variação de produto que o app não tem. Isso ocorre porque o plug-in simplesmente nunca solicita essa variação da dependência. |
Use Groovy// In the app's build.gradle file. android { defaultConfig{ // Do not configure matchingFallbacks in the defaultConfig block. // Instead, you must specify fallbacks for a given product flavor in the // productFlavors block, as shown below. } flavorDimensions 'tier' productFlavors { paid { dimension 'tier' // Because the dependency already includes a "paid" flavor in its // "tier" dimension, you don't need to provide a list of fallbacks // for the "paid" flavor. } free { dimension 'tier' // Specifies a sorted list of fallback flavors that the plugin // should try to use when a dependency's matching dimension does // not include a "free" flavor. You may specify as many // fallbacks as you like, and the plugin selects the first flavor // that's available in the dependency's "tier" dimension. matchingFallbacks = ['demo', 'trial'] } } } Kotlin// In the app's build.gradle file. android { defaultConfig{ // Do not configure matchingFallbacks in the defaultConfig block. // Instead, you must specify fallbacks for a given product flavor in the // productFlavors block, as shown below. } flavorDimensions += "tier" productFlavors { create("paid") { dimension = "tier" // Because the dependency already includes a "paid" flavor in its // "tier" dimension, you don't need to provide a list of fallbacks // for the "paid" flavor. } create("free") { dimension = "tier" // Specifies a sorted list of fallback flavors that the plugin // should try to use when a dependency's matching dimension does // not include a "free" flavor. You may specify as many // fallbacks as you like, and the plugin selects the first flavor // that's available in the dependency's "tier" dimension. matchingFallbacks += listOf("demo", "trial") } } } |
Uma dependência de biblioteca inclui uma dimensão de variação que o app não tem. Por exemplo, uma dependência de biblioteca inclui variações para uma dimensão "minApi", mas o app inclui variações apenas para a dimensão "tier" (nível). Então, quando você quiser criar a versão "freeDebug" (depuração sem custo financeiro) do app, o plug-in não saberá se precisa usar a versão "minApi23Debug" ou "minApi18Debug" da dependência. Observe que não há problema quando o app inclui uma dimensão de variação que uma dependência de biblioteca não tem. Isso ocorre porque o plug-in faz a correspondência de variações apenas nas dimensões que existem na dependência. Por exemplo, se uma dependência não incluir uma dimensão para ABIs, a versão "freeX86Debug" do app simplesmente usará a versão "freeDebug" da dependência. |
Use Groovy// In the app's build.gradle file. android { defaultConfig{ // Specifies a sorted list of flavors that the plugin should try to use from // a given dimension. The following tells the plugin that, when encountering // a dependency that includes a "minApi" dimension, it should select the // "minApi18" flavor. You can include additional flavor names to provide a // sorted list of fallbacks for the dimension. missingDimensionStrategy 'minApi', 'minApi18', 'minApi23' // You should specify a missingDimensionStrategy property for each // dimension that exists in a local dependency but not in your app. missingDimensionStrategy 'abi', 'x86', 'arm64' } flavorDimensions 'tier' productFlavors { free { dimension 'tier' // You can override the default selection at the product flavor // level by configuring another missingDimensionStrategy property // for the 'minApi' dimension. missingDimensionStrategy 'minApi', 'minApi23', 'minApi18' } paid {} } } Kotlin// In the app's build.gradle file. android { defaultConfig{ // Specifies a sorted list of flavors that the plugin should try to use from // a given dimension. The following tells the plugin that, when encountering // a dependency that includes a "minApi" dimension, it should select the // "minApi18" flavor. You can include additional flavor names to provide a // sorted list of fallbacks for the dimension. missingDimensionStrategy("minApi", "minApi18", "minApi23") // You should specify a missingDimensionStrategy property for each // dimension that exists in a local dependency but not in your app. missingDimensionStrategy("abi", "x86", "arm64") } flavorDimensions += "tier" productFlavors { create("free") { dimension = "tier" // You can override the default selection at the product flavor // level by configuring another missingDimensionStrategy property // for the "minApi" dimension. missingDimensionStrategy("minApi", "minApi23", "minApi18") } create("paid") {} } } |
Para mais informações, consulte matchingFallbacks e missingDimensionStrategy na referência de DSL do plug-in do Android.
Definir configurações de assinatura
O Gradle não assina o APK ou AAB do build de lançamento, a não ser que você defina explicitamente uma configuração de assinatura para esse build. Se você ainda não tiver uma chave de assinatura, veja como gerar uma chave de upload e um keystore usando o Android Studio.
Para definir manualmente as configurações de assinatura para seu tipo de build de lançamento usando as configurações de build do Gradle, siga estas etapas:
- Crie um keystore. Um keystore é um arquivo binário que contém um conjunto de chaves privadas. É necessário manter o keystore em um local seguro e protegido.
- Crie uma chave privada. Uma chave privada é usada para assinar seu app para distribuição e nunca é incluída no app nem divulgada a terceiros não autorizados.
-
Adicione a configuração de assinatura ao arquivo
build.gradle
do módulo:Groovy
... android { ... defaultConfig {...} signingConfigs { release { storeFile file("myreleasekey.keystore") storePassword "password" keyAlias "MyReleaseKey" keyPassword "password" } } buildTypes { release { ... signingConfig signingConfigs.release } } }
Kotlin
... android { ... defaultConfig {...} signingConfigs { create("release") { storeFile = file("myreleasekey.keystore") storePassword = "password" keyAlias = "MyReleaseKey" keyPassword = "password" } } buildTypes { getByName("release") { ... signingConfig = signingConfigs.getByName("release") } } }
Observação: incluir as senhas da chave de lançamento e do keystore dentro do arquivo de build não é uma prática de segurança recomendada. Como alternativa, você pode configurar o arquivo do build para extrair essas senhas de variáveis de ambiente ou fazer com que o processo de compilação as solicite.
Para receber essas senhas de variáveis de ambiente:
Groovy
storePassword System.getenv("KSTOREPWD") keyPassword System.getenv("KEYPWD")
Kotlin
storePassword = System.getenv("KSTOREPWD") keyPassword = System.getenv("KEYPWD")
Para que o processo de compilação solicite essas senhas se invocar o build a partir da linha de comando:
Groovy
storePassword System.console().readLine("\nKeystore password: ") keyPassword System.console().readLine("\nKey password: ")
Kotlin
storePassword = System.console().readLine("\nKeystore password: ") keyPassword = System.console().readLine("\nKey password: ")
Após a conclusão desse processo, você poderá distribuir seu app e publicá-lo no Google Play.
Aviso: mantenha o keystore e a chave privada em um local seguro e proteja os backups deles. Se você usar a Assinatura de apps do Google Play e perder sua chave de upload, poderá solicitar uma redefinição usando o Play Console. Se você estiver publicando um app sem a Assinatura de apps do Google Play (para apps criados antes de agosto de 2021) e perder a chave de assinatura do app, não será possível publicar nenhuma atualização, porque você precisa sempre assinar todas as versões do app com a mesma chave.
Assinatura de apps do Wear OS
Na publicação de apps do Wear OS, o APK do relógio e o APK opcional do smartphone precisam ser assinados. Para ver mais informações sobre o empacotamento e a assinatura de apps do Wear OS, consulte Empacotar e distribuir apps do Wear.