Como definir versionName no nome do arquivo APK usando gradle?

169

Estou tentando definir um número de versão específico no nome do arquivo APK gerado automaticamente pelo gradle.

Agora o gradle gera, myapp-release.apkmas eu quero que seja algo parecido myapp-release-1.0.apk.

Eu tentei renomear opções que parecem confusas. Existe uma maneira simples de fazer isso?

buildTypes {
    release {
       signingConfig signingConfigs.release
       applicationVariants.each { variant ->
       def file = variant.outputFile
       variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" +    defaultConfig.versionName + ".apk"))
    }
}

Eu tentei o código acima sem sorte. Alguma sugestão? (usando o gradle 1.6)

codaR0y
fonte

Respostas:

225

Eu só tenho que mudar o nome da versão em um só lugar. O código também é simples.

Os exemplos abaixo criarão arquivos apk chamados MyCompany-MyAppName-1.4.8-debug.apk ou MyCompany-MyAppName-1.4.8-release.apk, dependendo da variante de compilação selecionada.

Observe que esta solução funciona nos pacotes APK e App (arquivos .aab) .

Consulte também: Como alterar o nome do arquivo de mapeamento proguard em gradle para o projeto Android

Solução para o plugin Gradle recente

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"
    defaultConfig {
        applicationId "com.company.app"
        minSdkVersion 13
        targetSdkVersion 21
        versionCode 14       // increment with every release
        versionName '1.4.8'   // change with every release
        setProperty("archivesBaseName", "MyCompany-MyAppName-$versionName")
    }
}

A solução acima foi testada com as seguintes versões do Android Gradle Plugin:

  • 3.5.2 (novembro de 2019)
  • 3.3.0 (janeiro de 2019)
  • 3.1.0 (março de 2018)
  • 3.0.1 (novembro de 2017)
  • 3.0.0 (outubro de 2017)
  • 2.3.2 (maio de 2017)
  • 2.3.1 (abril de 2017)
  • 2.3.0 (fevereiro de 2017)
  • 2.2.3 (dezembro de 2016)
  • 2.2.2
  • 2.2.0 (setembro de 2016)
  • 2.1.3 (agosto de 2016)
  • 2.1.2
  • 2.0.0 (abril de 2016)
  • 1.5.0 (12/11/2015)
  • 1.4.0-beta6 (05/10/2015)
  • 1.3.1 (11/08/2015)

Vou atualizar este post à medida que novas versões forem lançadas.

Solução testada apenas nas versões 1.1.3-1.3.0

A solução a seguir foi testada com as seguintes versões do Android Gradle Plugin:

arquivo gradle do aplicativo:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"
    defaultConfig {
        applicationId "com.company.app"
        minSdkVersion 13
        targetSdkVersion 21
        versionCode 14       // increment with every release
        versionName '1.4.8'   // change with every release
        archivesBaseName = "MyCompany-MyAppName-$versionName"
    }
}
Jon
fonte
11
Eu acho que essa é a abordagem correta em vez de escrever outra tarefa para renomear arquivos.
Nandish A
5
basta alterar a archivesBaseName = "MyCompany-MyAppName- $ versionName" se você tem TOC e não AS quer avisá-lo sobre a +
ligi
4
Ótima descoberta, mas não funciona bem com sabores com códigos de versão diferentes. Todos eles terminam com o mesmo código de versão.
weston
2
Existe alguma maneira de adicionar variant.buildType.nameao nome? Eu sei que isso não configuração realmente padrão é relacionado, mas eu estou tentando descobrir como remover o obsoleto variantOutput.getAssemble()aviso
Allan W
2
É possível remover do nome do apk last '-debug' / '-release'?
Ilyamuromets
173

Isso resolveu meu problema: usar em applicationVariants.allvez deapplicationVariants.each

buildTypes {
      release {
        signingConfig signingConfigs.release
        applicationVariants.all { variant ->
            def file = variant.outputFile
            variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + defaultConfig.versionName + ".apk")) 
        }
    }       
}

Atualizar:

Parece que isso não funciona com as versões 0.14+ do plugin android studio gradle.

Isso faz o truque (referência desta pergunta ):

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.outputFile = new File(
                    output.outputFile.parent,
                    output.outputFile.name.replace(".apk", "-${variant.versionName}.apk"))
        }
    }
}
codaR0y
fonte
3
Você sabe como fazê-lo funcionar se eu tiver uma configuração versionNamedefinida em AndroidManifest.xmlvez de gradle? Isso me dá myapp-release-null.apkagora.
Iwo Banas
1
Esta resposta não funciona com versões 0.14+ do plug-in gradle. Alguma atualização para trabalhar com eles?
Argyle
1
@withoutclass Eu perguntei isso como se fosse uma pergunta própria e a resposta foi
Argyle
2
Para as pessoas que estão atualizando para o Gradle 4: altere eachpara alle output.outputFilepara outputFileName. Se alguém confims funciona este pode ser editado na resposta :)
PHPirate
6
@PHPirate: quase funciona:Error:(34, 0) Cannot set the value of read-only property 'name'
Mooing Duck
47

(EDITADO para funcionar com o Android Studio 3.0 e Gradle 4)

Eu estava procurando por uma opção de renomeação de nome de arquivo apk mais complexa e escrevi esta na esperança de que seja útil para qualquer outra pessoa. Renomeia o apk com os seguintes dados:

  • sabor
  • tipo de construção
  • versão
  • encontro

Levei um pouco de pesquisa nas aulas de graduação e um pouco de copiar / colar de outras respostas. Estou usando o gradle 3.1.3 .

No build.gradle:

android {

    ...

    buildTypes {
        release {
            minifyEnabled true
            ...
        }
        debug {
            minifyEnabled false
        }
    }

    productFlavors {
        prod {
            applicationId "com.feraguiba.myproject"
            versionCode 3
            versionName "1.2.0"
        }
        dev {
            applicationId "com.feraguiba.myproject.dev"
            versionCode 15
            versionName "1.3.6"
        }
    }

    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            def project = "myProject"
            def SEP = "_"
            def flavor = variant.productFlavors[0].name
            def buildType = variant.variantData.variantConfiguration.buildType.name
            def version = variant.versionName
            def date = new Date();
            def formattedDate = date.format('ddMMyy_HHmm')

            def newApkName = project + SEP + flavor + SEP + buildType + SEP + version + SEP + formattedDate + ".apk"

            outputFileName = new File(newApkName)
        }
    }
}

Se você compilar hoje (13-10-2016) às 10:47, obterá os seguintes nomes de arquivo, dependendo do tipo e tipo de construção que você escolheu:

  • dev debug : myProject_ dev_debug_1.3.6 _131016_1047.apk
  • liberação dev : myProject_ dev_release_1.3.6 _131016_1047.apk
  • depuração do prod : myProject_ prod_debug_1.2.0 _131016_1047.apk
  • liberação do prod : myProject_ prod_release_1.2.0 _131016_1047.apk

Nota: o nome do apk da versão desalinhada ainda é o nome padrão.

Fer
fonte
Ótima solução. Eu tentei e é perfeito para o meu problema. Obrigado!
Pabel
é possível usar a mesma abordagem no Xamarin Studio?
Alessandro Caliaro 01/12/16
Seria ótimo se fosse possível, mas estou iniciando agora um curso de Xamarin e ainda não tenho prática suficiente para saber se é possível ou não. Farei essa pergunta e virei aqui novamente.
Fer
Comentário do professor do curso: "existe uma opção em que você pode usar comandos para alterar o nome dos arquivos gerados". Portanto, a abordagem a ser usada no Xamarin deve ser diferente da que escrevi para o Android Studio, desculpe.
Fer
3
Para resolver o erro Não é possível definir o valor da propriedade somente leitura 'outputFile' - conforme mencionado em um comentário anterior por ter que "alterar eachpara alle output.outputFilepara outputFileName" - esta postagem fornece alguns detalhes sobre isso: stackoverflow.com/a/44265374/2162226
Gene Bo
19

Para resumir, para quem não sabe importar pacote build.gradle(como eu), use o seguinte buildTypes,

buildTypes {
      release {
        signingConfig signingConfigs.release
        applicationVariants.all { variant ->
            def file = variant.outputFile
            def manifestParser = new com.android.builder.core.DefaultManifestParser()
            variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile) + ".apk")) 
        }
    }       
}

===== EDIT =====

Se você definir seu versionCodee versionNameem seu build.gradlearquivo assim:

defaultConfig {
    minSdkVersion 15
    targetSdkVersion 19
    versionCode 1
    versionName "1.0.0"
}

Você deve configurá-lo assim:

buildTypes {   
        release {
            signingConfig signingConfigs.releaseConfig
            applicationVariants.all { variant ->
                def file = variant.outputFile
                variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + defaultConfig.versionName + ".apk"))
            }
        }
}


====== EDITAR com o Android Studio 1.0 ======

Se você estiver usando o Android Studio 1.0, você receberá um erro como este:

Error:(78, 0) Could not find property 'outputFile' on com.android.build.gradle.internal.api.ApplicationVariantImpl_Decorated@67e7625f.

Você deve alterar a build.Typesparte para isso:

buildTypes {
        release {
            signingConfig signingConfigs.releaseConfig
            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace(".apk", "-" + defaultConfig.versionName + ".apk"))
                }
            }
        }
    }
Wesley
fonte
Isso funciona muito bem. No entanto, como eu incremento minha versão do manifesto na compilação gradle, ele cria um APK com o valor mais antigo (pré-incremento). Alguma maneira de garantir que isso tenha efeito após o script gradle aumentar o número da versão?
Guy
1
@ Buy Desculpe, demorou tanto tempo. Eu editei a resposta, veja se ele pode resolver seu problema.
Wesley
17

Se você não especificar versionName no bloco defaultConfig, defaultConfig.versionNameresultará emnull

Para obter versionName do manifesto, você pode escrever o seguinte código em build.gradle:

import com.android.builder.DefaultManifestParser

def manifestParser = new DefaultManifestParser()
println manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
Arkadiusz Konior
fonte
7
Acredito que com versões posteriores do Gradle, é agora com.android.builder.core.DefaultManifestParser
Ryan S
8

No meu caso, eu só queria encontrar uma maneira de automatizar a geração de apknomes releasee debugvariantes diferentes. Consegui fazer isso facilmente colocando esse snippet como filho de android:

applicationVariants.all { variant ->
    variant.outputs.each { output ->
        def appName = "My_nice_name_"
        def buildType = variant.variantData.variantConfiguration.buildType.name
        def newName
        if (buildType == 'debug'){
            newName = "${appName}${defaultConfig.versionName}_dbg.apk"
        } else {
            newName = "${appName}${defaultConfig.versionName}_prd.apk"
        }
        output.outputFile = new File(output.outputFile.parent, newName)
    }
}

Para o novo Android gradle plugin 3.0.0, você pode fazer algo assim:

 applicationVariants.all { variant ->
    variant.outputs.all {
        def appName = "My_nice_name_"
        def buildType = variant.variantData.variantConfiguration.buildType.name
        def newName
        if (buildType == 'debug'){
            newName = "${appName}${defaultConfig.versionName}_dbg.apk"
        } else {
            newName = "${appName}${defaultConfig.versionName}_prd.apk"
        }
        outputFileName = newName
    }
}

Isso produz algo como: My_nice_name_3.2.31_dbg.apk

yshahak
fonte
6

Outra alternativa é usar o seguinte:

String APK_NAME = "appname"
int VERSION_CODE = 1
String VERSION_NAME = "1.0.0"

project.archivesBaseName = APK_NAME + "-" + VERSION_NAME;

    android {
      compileSdkVersion 21
      buildToolsVersion "21.1.1"

      defaultConfig {
        applicationId "com.myapp"
        minSdkVersion 15
        targetSdkVersion 21
        versionCode VERSION_CODE
        versionName VERSION_NAME
      }

       .... // Rest of your config
}

Isso definirá "appname-1.0.0" para todas as suas saídas apk.

Marco RS
fonte
Desculpe não funciona (por mais tempo): No such property: archivesBaseName for class: org.gradle.api.internal.project.DefaultProject_Decorated
Martin
Qual versão gradle você está usando?
Marco RS
6

Gradle 6+

Agora estou usando o seguinte no Android Studio 4.0 e Gradle 6.4:

android {
    defaultConfig {
        applicationId "com.mycompany.myapplication"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 15
        versionName "2.1.1"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            applicationVariants.all { variant ->
                variant.outputs.all {
                    outputFileName = "ApplicationName-${variant.name}-${variant.versionName}.apk"
                }
            }
        }
    }
}

Gradle 4

A sintaxe mudou um pouco no Gradle 4 (Android Studio 3+) (de output.outputFilepara outputFileName, a idéia desta resposta agora é:

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def newName = outputFileName
            newName.replace(".apk", "-${variant.versionName}.apk")
            outputFileName = new File(newName)
        }
    }
}
PHPirate
fonte
Alguma idéia de como consertar isso para o gradle 6?
spartygw 10/06
@spartygw Atualizou a resposta
PHPirate 10/06
5

A maneira certa de renomear o apk, de acordo com a resposta do @Jon

defaultConfig {
        applicationId "com.irisvision.patientapp"
        minSdkVersion 24
        targetSdkVersion 22
        versionCode 2  // increment with every release
        versionName "0.2" // change with every release
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        //add this line
        archivesBaseName = "AppName-${versionName}-${new Date().format('yyMMdd')}"
    }   

Ou outra maneira de obter os mesmos resultados com

android {
    ...

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            def formattedDate = new Date().format('yyMMdd')
            outputFileName = "${outputFileName.replace(".apk","")}-v${defaultConfig.versionCode}-${formattedDate}.apk"
        }
    }
}
Qamar
fonte
Bom sobre isso! Eu gosto mais disso do que de outras maneiras que estou fazendo atualmente.
Droid Chris
3

Existem muitas respostas corretas na íntegra ou após algumas modificações. Mas vou adicionar o meu de qualquer maneira, pois estava tendo o problema com todos eles porque estava usando scripts para gerar VersionName e VersionCode dinamicamente, conectando-me à preBuildtarefa.

Se você estiver usando alguma abordagem semelhante, este é o código que funcionará:

project.android.applicationVariants.all { variant ->
    variant.preBuild.doLast {
    variant.outputs.each { output ->
        output.outputFile = new File(
                output.outputFile.parent,
                output.outputFile.name.replace(".apk", "-${variant.versionName}@${variant.versionCode}.apk"))
        }
    }
}

Para explicar: Como estou substituindo o código e o nome da versão na primeira ação de preBuild, tenho que adicionar o arquivo renomeado ao final desta tarefa. Então, o que o gradle fará neste caso é:

Injetar código de versão / nome-> executar ações de pré-construção -> substituir nome para apk

Igor Čordaš
fonte
Onde você está configurando as variáveis ​​versionCode e versionName geradas?
Mars
Pelo que me lembro, isso foi feito dentro do nosso plugin gradle personalizado. Sua execução foi chamada como última ação da tarefa preBuild.
Igor Čordaš
2
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk")
        }
    }
timeon
fonte
Embora esse trecho de código possa resolver a questão, incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se de que você está respondendo à pergunta dos leitores no futuro e essas pessoas podem não saber os motivos da sua sugestão de código.
Rosário Pereira Fernandes
1

No meu caso, resolvo esse erro dessa maneira

adicionando um SUFIXO à versão Debug, neste caso, adicionando o texto "-DEBUG" à minha implantação de Debug

 buildTypes {
        release {

            signingConfig signingConfigs.release
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'


        }
        debug {

            defaultConfig {
                debuggable true

                versionNameSuffix "-DEBUG"
            }
        }
    }
exequielc
fonte
Isso não altera o nome do arquivo APK.
Tom
1
Esta é uma boa dica, na verdade. Não está na pergunta certa, mas é boa. Onde posso ler mais sobre isso? É possível usar com versionNameSuffixbase no ramo GIT? Por exemplo, se não estiver no "master", sempre tenha um sufixo, mesmo que seja uma versão de lançamento
desenvolvedor android
0

Para as versões mais recentes do gradle, você pode usar o seguinte snippet:

Defina primeiro o local do manifesto do aplicativo

 sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
        {
    }

E mais tarde no build.gradle

import com.android.builder.core.DefaultManifestParser

def getVersionName(manifestFile) {
    def manifestParser = new DefaultManifestParser();
    return manifestParser.getVersionName(manifestFile);
}

def manifestFile = file(android.sourceSets.main.manifest.srcFile);
def version = getVersionName(manifestFile)

buildTypes {
    release {
       signingConfig signingConfigs.release
       applicationVariants.each { variant ->
       def file = variant.outputFile
       variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" +    versionName + ".apk"))
    }
}

Ajuste se você tiver manifestos diferentes por tipo de construção. mas desde que eu tenho o single - funciona perfeitamente para mim.

Alfishe
fonte
é possível adicionar uma string de um arquivo de classe ao nome do apk?
Upendra Shah
0

No Android Studio 1.1.0, encontrei essa combinação no corpo do arquivo androidbuild.gradle . Isto é, se você não conseguir descobrir como importar os dados do arquivo xml do manifesto. Eu gostaria que fosse mais suportado pelo Android Studio, mas brinque com os valores até obter a saída desejada do nome do apk:

defaultConfig {
        applicationId "com.package.name"
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 6
        versionName "2"
    }
    signingConfigs {
        release {
            keyAlias = "your key name"
        }
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            signingConfig signingConfigs.release
            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace("app-release.apk", "appName_" + versionName + ".apk"))
                }
            }
        }
    }
A13X
fonte