Migrar para o Android Plugin for Gradle 3.0.0

Problema conhecido: se você tiver um projeto existente do Android Studio que use uma versão alfa do Android Plugin 3.0.0 (como o 3.0.0-alpha9), é possível que você receba o erro a seguir ao migrar para o Android Plugin 3.0.0-beta4 e sincronizar seu projeto: Gradle project refresh failed.

Solucione esse problema selecionando Build > Clean Project na barra de menus. Basta realizar essa ação uma vez para cada projeto. Você poderá, então, sincronizar os arquivos do projeto com o Gradle clicando em Sync Project na barra de menus.

Se quiser migrar seu projeto para o Android Plugin 3.0.0-beta4 ou uma versão posterior, leia esta página para saber como aplicar o plug-in e a versão específica do Gradle e adaptar seu projeto a algumas mudanças importantes.

Atualizar a versão do Gradle

O novo Android Plugin exige versão 4.1-rc-1 ou posterior do Gradle. Se você estiver abrindo um projeto existente usando o Android Studio 3.0 Beta 1 ou posterior, siga as instruções para atualizar automaticamente um projeto existente para a versão compatível do Gradle.

Para atualizar o Gradle manualmente, atualize o URL em gradle-wrapper.properties da seguinte maneira:

distributionUrl=\
  https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip

Aplicar o plug-in

Se você estiver abrindo um projeto existente usando o Android Studio 3.0 Beta 1 ou posterior, siga as instruções para atualizar automaticamente seu projeto para a versão mais recente do Android Plugin. Para atualizar manualmente seu projeto, inclua o repositório maven e altere a versão do plug-in no arquivo build.gradle de nível do projeto da seguinte maneira:

buildscript {
    repositories {
        ...
        // You need to add the following repository to download the
        // new plugin.
        google()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0-beta4'
    }
}

Use dimensões de variação para o gerenciamento de dependências com reconhecimento de variantes

O Plugin 3.0.0 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 aplicativo automaticamente consome a variante debug de uma biblioteca e assim por diante. Isso também funciona ao usar variações: a variante redDebug de um aplicativo consumirá a variante redDebug de uma biblioteca. Para que isso funcione, o plug-in agora exige que todas as variações pertencem a uma dimensão de variação nomeada, mesmo que você pretenda usar uma só dimensão. Caso contrário, você receberá o seguinte erro de compilação:

Error:All flavors must now belong to a named flavor dimension.
The flavor 'flavor_name' is not assigned to a flavor dimension.

Para solucionar esse erro, atribua cada variação para uma dimensão nomeada, conforme é mostrado no exemplo abaixo. Como a correspondência de dependência é agora realizada pelo plug-in, você deve nomear suas dimensões de variação com cuidado. Por exemplo, se todos os seus módulos de aplicativo e biblioteca usarem a dimensão foo, você terá menos controle sobre quais variações são correspondidas pelo plug-in.

// Specifies a flavor dimension.
flavorDimensions "color"

productFlavors {
     red {
      // Assigns this product flavor to the 'color' flavor dimension.
      // This step is optional if you are using only one dimension.
      dimension "color"
      ...
    }

    blue {
      dimension "color"
      ...
    }
}

Solucionar erros de compilação relacionados à correspondência de dependências

O Android Plugin tenta fazer a correspondência de cada variante do seu aplicativo com a mesma variante da biblioteca. Portanto, quando você compilar uma versão "freeDebug" do seu aplicativo, o plug-in tentará correspondê-la a versões "freeDebug" das dependências de sua biblioteca local.

Entretanto, considere se seu aplicativo configura um tipo de compilação chamado "staging", mas uma de suas dependências de biblioteca não. Quando o plug-in tentar compilar a versão "staging" do aplicativo, ele não saberá qual versão da biblioteca usar e você verá uma mensagem de erro semelhante à seguinte:

Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
    project :app

O Android Plugin 3.0.0-beta4 e versões posteriores incluem elementos DSL para ajudar a controlar como o plug-in deve solucionar situações nas quais uma correspondência direta de variante entre um aplicativo e uma dependência não é possível. A tabela abaixo ajuda você a determinar qual propriedade de DSL você deve usar para solucionar certos erros de compilação relacionados à correspondência de dependências com reconhecimento de variantes.

Causa do erro de compilaçãoSolução

Seu aplicativo inclui um tipo de compilação que uma dependência de biblioteca não tem.

Por exemplo, seu aplicativo inclui um tipo de compilação “staging”, mas uma dependência inclui somente tipos de compilação "debug" e "release".

Observe que não há problema quando uma dependência de biblioteca inclui um tipo de se compilação que seu aplicativo não tem. Isso ocorre porque o plug-in simplesmente nunca solicitará esse tipo de compilação da dependência.

Use matchingFallbacks para especificar correspondências alternativas para um determinado tipo de compilação, conforme é mostrado abaixo:
// 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']
        }
    }
}

Para uma determinada dimensão de variação que existe no aplicativo e na sua dependência de biblioteca, seu aplicativo inclui variações que a biblioteca não tem.

Por exemplo, tanto o aplicativo quanto suas dependências de biblioteca incluem uma dimensão de variação "tier". Entretanto, a dimensão "tier" no aplicativo inclui variações "free" e "paid", mas uma dependência inclui somente variações "demo" e "paid" para a mesma dimensão.

Observe que, para uma determinada dimensão de variação que existe no aplicativo e nas dependências de biblioteca, não há problema quando uma biblioteca inclui uma variação de produto que o aplicativo não tem. Isso ocorre porque o plug-in simplesmente nunca solicitará essa variação da dependência.

Use matchingFallbacks para especificar correspondências alternativas para a variação de produto "free" do aplicativo, conforme é mostrado abaixo:
// 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']
        }
    }
}

Uma dependência de biblioteca inclui uma dimensão de variação que o aplicativo não tem.

Por exemplo, uma dependência de biblioteca inclui variações para uma dimensão "minApi”, mas seu aplicativo inclui variações para apenas a dimensão "tier". Portanto, quando você quiser compilar a versão "freeDebug" do seu aplicativo, o plug-in não saberá se deve usar a versão "minApi23Debug" ou "minApi18Debug" da dependência.

Observe que não há problema quando seu aplicativo inclui uma dimensão de variação que uma dependência de biblioteca não tem. Isso ocorre porque o plug-in corresponde variações de apenas as 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 aplicativo simplesmente usaria a versão "freeDebug" da dependência.

Use missingDimensionStrategy no bloco defaultConfig para especificar a variação padrão que o plug-in deve selecionar de cada dimensão ausente, conforme é mostrado no exemplo abaixo. Você também pode modificar suas seleções no bloco productFlavors, de forma que cada variação possa especificar uma estratégia de correspondência diferente para uma dimensão ausente.
// 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 {}
    }
}

Migrar configurações de dependência para módulos locais

Se você configurou corretamente suas dimensões de variação para aproveitar as vantagens da resolução de dependências com reconhecimento de variante, você não mais precisa usar configurações específicas de variante, como redDebugImplementation, para dependências locais de módulo, pois o plug-in faz isso para você. O uso de configurações específicas de variante é opcional e não invalida sua compilação.

Entretanto, direcionar para uma variante específica de uma dependência de módulo local (por exemplo, usando configuration: 'debug') causa o seguinte erro de compilação:

Error:Could not resolve all dependencies for configuration
  ':app:prodDebugCompileClasspath'.
Project :app declares a dependency from configuration 'compile'
  to configuration 'debug' which is not declared in the descriptor
  for project :foo.

Em vez disso, você deve configurar suas dependências da seguinte maneira:

dependencies {
    // This is the old method and no longer works for local
    // library modules:
    // debugCompile project(path: ':foo', configuration: 'debug')
    // releaseCompile project(path: ':foo', configuration: 'release')

    // Instead, simply use the following to take advantage of
    // variant-aware dependency resolution. You can learn more about
    // the 'implementation' configuration in the section about
    // new dependency configurations.
    implementation project(':foo')

    // You can, however, keep using variant-specific configurations when
    // targeting external dependencies. The following line adds 'app-magic'
    // as a dependency to only the 'debug' version of your module.

    debugImplementation 'com.example.android:app-magic:12.3'
}

Observação: não é mais possível usar com facilidade o mecanismo antigo para uma dependência de variante manual, mesmo que a Gradle API para ela ainda esteja presente. A configuração fornecida ao project() DSL agora deve corresponder o consumidor em termos de tipo de compilação e variações (e outros atributos). Por exemplo, não é possível fazer com que uma variante “debug” consuma uma variante “release” por meio desse mecanismo, pois o produtor e o consumidor não correspondem. (Nesse caso, o nome “debug” refere-se ao objeto de configuração publicado mencionado acima na seção Dependências de publicação.) Agora que publicamos duas configurações, uma para a compilação e outra para o tempo de execução, essa forma antiga de selecionar uma configuração não funcionará mais.

Configurar dependências do aplicativo Wear

Para oferecer suporte à resolução de dependências com reconhecimento de variante para aplicativos wear incorporados, o Plugin 3.0.0 agora combina todos os gráficos antes de resolvê-los, semelhante a como outras dependências são processadas. Em versões anteriores do plug-in, gráficos de dependências <component>WearApp eram resolvidos separadamente. Portanto, por exemplo, você poderia fazer algo como o exemplo a seguir, e as variantes azuis usariam :wear2 e todas as demais variantes usariam :wear1:

dependencies {
    // This is the old way of configuring Wear App dependencies.
    wearApp project(':wear1')
    blueWearApp project(':wear2')
}

A configuração acima não funciona mais com o novo plug-in. Entretanto, se seu módulo wearable configurar as mesmas variações que seu aplicativo principal, não será necessário usar a configuração <flavor>WearApp. Basta especificar a configuração wearApp e cada variante do aplicativo principal consumirá a variante correspondente de wearable:

dependencies {
    // If the main app and wearable modules have the same flavors,
    // the following configuration uses automatic dependency matching.
    wearApp  project(':wearable')
}

Se quiser especificar um módulo de aplicativo Wear diferente por variação de aplicativo, ainda será possível usar a configuração <flavor>WearApp da seguinte maneira (no entanto, não é possível combiná-lo com a configuração wearApp):

dependencies {
    redWearApp project(':wear1')
    greenWearApp project(':wear1')
    blueWearApp project(':wear2')
}

Usar as novas configurações de dependência

O Gradle 3.4 introduziu novas configurações de plug-in da Biblioteca Java que permitem controle sobre a publicação para caminhos de classe de compilação e tempo de execução (para dependências entre módulos). O Android Plugin 3.0.0 está passando para essas novas configurações de dependência. Para migrar seu projeto, basta atualizar suas dependências para usar as novas configurações em vez das obsoletas, conforme é descrito na tabela abaixo.

Nova configuração Configuração obsoleta Comportamento
implementation compile A dependência está disponível para o módulo no tempo de compilação e ela está disponível para o consumidor do módulo apenas no tempo de execução. Para grandes compilações de vários projetos, o uso de implementation em vez de api/compile pode resultar em significativas melhoras no tempo de compilação, pois isso reduz a quantidade de projetos que o sistema de compilação precisa recompilar. A maioria dos módulos de teste e aplicativos deve usar essa configuração.
api compile A dependência está disponível para o módulo no tempo de compilação e também está disponível para o consumidor do módulo no tempo de execução e de compilação. Essa configuração se comporta da mesma forma que compile (que agora está obsoleta), e você normalmente deve usar essa configuração apenas em módulos de biblioteca. Módulos de aplicativos devem usar implementation, a não ser que você deseje expor sua API para um módulo de teste separado.
compileOnly provided A dependência está disponível para o módulo somente no tempo de compilação e não está disponível para os consumidores no tempo de compilação ou de execução. Essa configuração se comporta da mesma forma que provided (que agora esta obsoleta).
runtimeOnly apk A dependência está disponível para o módulo e para seus consumidores somente no tempo de execução. Essa configuração se comporta da mesma forma que apk (que agora esta obsoleta).

Assim como as versões estáveis atuais do Android Plugin, as configurações acima estão disponíveis para dependências específicas de tipo de compilação ou variação. Por exemplo, é possível usar api para disponibilizar a dependência para todas as variantes, ou usar redApi para disponibilizá-la somente para as variantes red do módulo.

Observação: compile, provided, e apk ainda estão disponíveis. No entanto, elas desaparecerão na próxima grande versão do Android Plugin.

Dependências de publicação

As configurações a seguir contêm as dependências transitivas de uma biblioteca para o consumo dos consumidores:

  • <variant>ApiElements
  • <variant>RuntimeElements

Havia uma só configuração por variante chamada <variant>. Como uma biblioteca agora pode controlar o que os consumidores veem para compilação, usando as configurações implementation e api descritas em uma seção anterior, agora há duas configurações, uma para a compilação dos consumidores e uma para o tempo de execução.

Para saber mais sobre as relações entre as diferentes configurações, acesse as configurações de plug-in da Biblioteca Java.

Migrar estratégias de resolução de dependências personalizadas

O plug-in usa as seguintes configurações para resolver todas as dependências de uma variante:

  • <variant>CompileClasspath (_<variant>Compile não funciona mais)
  • <variant>RuntimeClasspath (_<variant>Apk não funciona mais)

Se você ainda estiver usando as configurações antigas, você receberá um erro semelhante ao seguinte:

Error:Configuration with old name _debugCompile found.
Use new name debugCompileClasspath instead.

Plug-ins ou arquivos de compilação que definem uma estratégia de resolução na configuração resolvida precisará se adaptar ao novo nome. Devido à resolução atrasada de dependências, agora é possível definir a estratégia de resolução usando a API da variante, conforme é mostrado no exemplo abaixo. (O Android Plugin agora inclui getters para acessar os objetos de configuração de uma variante.)

// Previously, you had to apply a custom resolution strategy during the
// configuration phase, rather than in the execution phase. That's
// because, by the time the variant was created and the Variant API was
// called, the dependencies were already resolved. This no longer works, and
// you should use this method only while using an older version of the plugin.
// configurations {
//     _debugCompile
//     _debugApk
// }
// ...
//
// configurations._debugCompile.resolutionStrategy {
//     ...
// }
//
// configurations.all {
//     resolutionStrategy {
//     ...
//     }
// }

// Because the new build model delays dependency resolution, you should
// query and modify the resolution strategy using the Variant API.
android {
    applicationVariants.all { variant ->
        variant.getCompileConfiguration().resolutionStrategy {
            ...
        }
        variant.runtimeConfiguration.resolutionStrategy {
            ...
        }
        variant.getAnnotationProcessorConfiguration().resolutionStrategy {
            ...
        }
    }
}

Observação: no momento, o novo plug-in busca configurações que usam o nome antigo e ele falhará se as encontrar. Caso contrário, ele ignorará silenciosamente a estratégia de resolução personalizada. Isso poderá ser alterado com base em feedback, mas queremos encontrar uma maneira de facilitar a migração.

Usar a configuração de dependências do processador de anotações

Em versões anteriores do Android Plugin for Gradle, dependências no caminho de classe de compilação foram automaticamente adicionadas ao caminho de classe do processador. Ou seja, você pode adicionar um processador de anotações ao caminho de classe de compilação e ele funcionará da forma esperada. Entretanto, isso causa um impacto significativo no desempenho ao adicionar uma grande quantidade de dependências desnecessárias ao processador.

Ao usar o novo plug-in, os processadores de anotações devem ser adicionados ao caminho de classe do processador usando a configuração de dependência annotationProcessor, conforme é mostrado abaixo:

dependencies {
    ...
    annotationProcessor 'com.google.dagger:dagger-compiler:<version-number>'
}

O plug-in presume que uma dependência é um processador de anotações se seu arquivo JAR contiver o seguinte arquivo: META- INF/services/javax.annotation.processing.Processor. Se o plug-in detectar processadores de anotações no caminho de classe de compilação, a compilação falhará e você receberá uma mensagem de erro que lista cada processador de anotações no caminho de classe de compilação. Para corrigir o erro, basta alterar a configuração dessa dependências para usar annotationProcessor. Se uma dependência incluir componentes que também precisam estar no caminho de classe de compilação, declare essa dependência uma segunda vez e use a configuração de dependência compile.

Usuários do plug-in android-apt: no momento, essa mudança de comportamento não afeta o plug-in android-apt. No entanto, o plug-in não será compatível com versões futuras do Android Plugin for Gradle.

Desativar a verificação de erros

Se você tiver dependências no caminho de classe de compilação que inclui processadores de anotações dos quais você não precisa, é possível desativar a verificação de erros ao adicionar o seguinte ao arquivo build.gradle. Lembre-se de que os processadores de anotações adicionados ao caminho de classe de compilação ainda não serão adicionados ao caminho de classe do processador.

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                includeCompileClasspath false
            }
        }
    }
}

Se você tiver problemas para migrar para a nova estratégia de resolução de dependências, é possível restaurar o comportamento para o do Android Plugin 2.3 ao definir includeCompileClasspath true. Entretanto, restaurar o comportamento para a versão 2.3 não é recomendável e a opção para fazer isso será removida em uma atualização futura. Para nos ajudar a melhorar a compatibilidade com as dependências que você está usando, registre um bug.

Usar módulos de teste separados

Módulos de teste separados agora reconhecem variantes (veja a seção acima) ao usar o Plugin 3.0.0. Isso significa que não é mais necessário especificar targetVariant.

Cada variante no módulo de teste tentará testar uma variante correspondente no projeto de destino. Por padrão, os módulos de teste contêm apenas uma variante debug, mas você pode criar novos tipos de compilação e novas variações para criar novas variantes para corresponder o projeto de aplicativo testado. Uma tarefa connectedCheck é criada para cada variante.

Para fazer o projeto Test testar somente um tipo de compilação diferente, e não um de depuração, use VariantFilter para desativar a variante debug no projeto de teste, conforme é mostrado abaixo:

android {
    variantFilter { variant ->
        if (variant.buildType.name.equals('debug') {
            variant.setIgnore(true);
        }
    }
}

Se quiser que um módulo de teste seja direcionado somente certas variantes de um aplicativo, pode usar propriedades flavorSelection para direcionar para as variações que deseja testar. Isso também impede que o módulo de teste precise configurar essas variações por conta própria.

JARs locais em bibliotecas

Anteriormente, módulos de biblioteca processavam dependências em JARs locais de forma não padrão e as empacotaria no AAR. Mesmo em um compilação de vários projetos, consumidores do AAR veriam esses arquivos JAR com a versão empacotada.

O Android Plugin 3.0.0 e versões posteriores usam as novas APIs do Gradle para permitir que projetos de consumo vejam os JARs locais como dependências transitivas regulares, semelhante a dependências com base em coordenadas do maven. Para adaptar-se para as novas APIs do Gradle, o plug-in precisou mudar alguns aspectos de como ele lida com arquivos JAR locais.

Publicação entre projetos

  • Módulos de biblioteca não mais processam JARs locais. Isso é feito para agilizar as compilações incrementais que são causadas por mudanças no código do módulo de biblioteca.

  • Transformações em módulos de biblioteca agora podem afetar apenas o escopo PROJECT. A aplicação de transformações com PROJECT_LOCAL_DEPS falharão, pois esse escopo agora está obsoleto.

  • Para módulos de aplicativos cujos JARs locais fazem parte do stream EXTERNAL, os streams PROJECT_LOCAL_DEPS e SUB_PROJECT_LOCAL_DEPS agora estão sempre vazios.

  • Ativar o ProGuard para módulos de biblioteca locais não mais afeta o código da biblioteca. Em vez disso, você deve executar o ProGuard no módulo de aplicativo final.

  • Anteriormente, conflitos de recursos Java entre um módulo de biblioteca e as dependências do JAR local precisavam ser resolvidos no módulo de biblioteca. Como os JARs locais não são mais processados pelo módulo de biblioteca, o conflito deve ser resolvido no aplicativo que consome a biblioteca.

Publicar no repositório Maven

  • Nada mudou na publicação em um repositório Maven. Os JARs locais são reunidos e seus recursos sem classe mesclados no arquivo JAR principal do AAR. Se o módulo ativar o ProGuard, todos os JARs serão mesclados no arquivo JAR principal.

Mudanças na API

O Android Plugin 3.0.0 introduz mudanças de API que remove certas funcionalidades e pode invalidar suas compilações existentes. Versões posteriores do plug-in podem introduzir novas APIs públicas que substituem funcionalidades inválidas.

Saída de variantes

O uso da Variant API para manipular saídas de variantes é invalidado com o novo plug-in. Ela ainda funciona para tarefas simples, como alterar o nome do APK durante o tempo de compilação, conforme é mostrado abaixo:

// If you use each() to iterate through the variant objects,
// you need to start using all(). That's because each() iterates
// through only the objects that already exist during configuration time—
// but those object don't exist at configuration time with the new model.
// However, all() adapts to the new model by picking up object as they are
// added during execution.
android.applicationVariants.all { variant ->
    variant.outputs.all {
        outputFileName = "${variant.name}-${variant.versionName}.apk"
    }
}

Entretanto, tarefas mais complicadas que envolvem o acesso a objetos outputFile não funcionam mais. Isso ocorre porque tarefas específicas de variante não são mais criadas durante a fase de configuração. Isso faz com que o plug-in não conheça todas as suas saídas imediatamente, mas também gera tempos de configuração mais rápidos.

manifestOutputFile

O método processManifest.manifestOutputFile() não está mais disponível, e você receberá o seguinte erro se tentar chamá-lo:

A problem occurred configuring project ':myapp'.
   Could not get unknown property 'manifestOutputFile' for task ':myapp:processDebugManifest'
   of type com.android.build.gradle.tasks.ProcessManifest.

Em vez de chamar manifestOutputFile() para obter o arquivo de manifesto para cada variante, você pode chamar processManifest.manifestOutputDirectory() para retornar o caminho do diretório que contém todos os manifesto gerado. Então, você pode localizar um manifesto e aplicar sua lógica a ele. O exemplo abaixo altera o código de versão dinamicamente no manifesto:

android.applicationVariants.all { variant ->
    variant.outputs.all { output ->
        output.processManifest.doLast {
            // Stores the path to the maifest.
            String manifestPath = "$manifestOutputDirectory/AndroidManifest.xml"
            // Stores the contents of the manifest.
            def manifestContent = file(manifestPath).getText()
            // Changes the version code in the stored text.
            manifestContent = manifestContent.replace('android:versionCode="1"',
                    String.format('android:versionCode="%s"', generatedCode))
            // Overwrites the manifest with the new text.
            file(manifestPath).write(manifestContent)
        }
    }
}