¿Cómo configurar versionName en el nombre de archivo APK usando gradle?

169

Estoy tratando de establecer un número de versión específico en el nombre de archivo APK generado automáticamente de Gradle.

Ahora gradle genera myapp-release.apkpero quiero que se vea algo así myapp-release-1.0.apk.

He intentado renombrar opciones que parecen desordenadas. ¿Hay una manera simple de hacer esto?

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"))
    }
}

He intentado el código anterior sin suerte. ¿Alguna sugerencia? (usando gradle 1.6)

codaR0y
fuente

Respuestas:

225

Solo tengo que cambiar el nombre de la versión en un solo lugar. El código también es simple.

Los ejemplos a continuación crearán archivos apk llamados MyCompany-MyAppName-1.4.8-debug.apk o MyCompany-MyAppName-1.4.8-release.apk dependiendo de la variante de compilación seleccionada.

Tenga en cuenta que esta solución funciona tanto en APK como en paquetes de aplicaciones (archivos .aab) .

Ver también: Cómo cambiar el nombre del archivo de mapeo proguard en gradle para proyecto Android

Solución para el complemento Gradle reciente

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")
    }
}

La solución anterior se ha probado con las siguientes versiones de Android Gradle Plugin:

  • 3.5.2 (noviembre de 2019)
  • 3.3.0 (enero de 2019)
  • 3.1.0 (marzo de 2018)
  • 3.0.1 (noviembre de 2017)
  • 3.0.0 (octubre de 2017)
  • 2.3.2 (mayo de 2017)
  • 2.3.1 (abril de 2017)
  • 2.3.0 (febrero de 2017)
  • 2.2.3 (diciembre de 2016)
  • 2.2.2
  • 2.2.0 (septiembre de 2016)
  • 2.1.3 (agosto de 2016)
  • 2.1.2
  • 2.0.0 (abril de 2016)
  • 1.5.0 (2015/11/12)
  • 1.4.0-beta6 (05/10/2015)
  • 1.3.1 (2015/08/11)

Actualizaré esta publicación a medida que salgan nuevas versiones.

Solución probada solo en las versiones 1.1.3-1.3.0

La siguiente solución ha sido probada con las siguientes versiones de Android Gradle Plugin:

archivo gradle de la aplicación:

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
fuente
11
Creo que este es el enfoque correcto en lugar de escribir otra tarea para cambiar el nombre de los archivos.
Nandish A
55
simplemente cambie a archivesBaseName = "MyCompany-MyAppName- $ versionName" si tiene TOC y no desea que AS le advierta sobre el +
ligi
44
Gran descubrimiento, pero no funciona bien con sabores con diferentes códigos de versión. Todos terminan con el mismo código de versión.
Weston
2
¿Hay alguna forma de agregar variant.buildType.nameal nombre? Sé que esto no está realmente relacionado con la configuración predeterminada, pero estoy tratando de descubrir cómo eliminar la variantOutput.getAssemble()advertencia obsoleta
Allan W
2
¿Es posible eliminar del último nombre de apk '-debug' / '-release'?
ilyamuromets
173

Esto resolvió mi problema: usar en applicationVariants.alllugar 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")) 
        }
    }       
}

Actualizar:

Por lo tanto, parece que esto no funciona con las versiones 0.14+ de Android Studio Gradle Plugin.

Esto hace el truco (Referencia de esta pregunta ):

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.outputFile = new File(
                    output.outputFile.parent,
                    output.outputFile.name.replace(".apk", "-${variant.versionName}.apk"))
        }
    }
}
codaR0y
fuente
3
¿Sabes cómo hacerlo funcionar si tengo una configuración versionNamedefinida en AndroidManifest.xmllugar de gradle? Me da myapp-release-null.apkahora
Iwo Banas
1
Esta respuesta no funciona con las versiones 0.14+ del complemento gradle. ¿Alguna actualización para trabajar con esos?
Argyle
1
@withoutclass Hice esto como su propia pregunta y obtuve respuesta aquí: stackoverflow.com/questions/27068505/…
Argyle
2
Para las personas que actualizan a Gradle 4: cambie eacha ally output.outputFilehacia outputFileName. Si alguien confirma que esto funciona, puede editarlo en la respuesta :)
PHPirate
66
@PHPirate: casi funciona:Error:(34, 0) Cannot set the value of read-only property 'name'
Mooing Duck
47

(EDITADO para trabajar con Android Studio 3.0 y Gradle 4)

Estaba buscando una opción de cambio de nombre de archivo apk más compleja y escribí esta con la esperanza de que sea útil para cualquier otra persona. Cambia el nombre del apk con los siguientes datos:

  • sabor
  • tipo de construcción
  • versión
  • fecha

Me tomó un poco de investigación en clases de gradle y un poco de copiar / pegar de otras respuestas. Estoy usando gradle 3.1.3 .

En el 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)
        }
    }
}

Si compila hoy (13-10-2016) a las 10:47, obtendrá los siguientes nombres de archivos según el sabor y el tipo de compilación que haya elegido:

  • depuración de desarrollo : myProject_ dev_debug_1.3.6 _131016_1047.apk
  • versión de desarrollo : myProject_ dev_release_1.3.6 _131016_1047.apk
  • depuración de productos : myProject_ prod_debug_1.2.0 _131016_1047.apk
  • lanzamiento de producto : myProject_ prod_release_1.2.0 _131016_1047.apk

Nota: el nombre apk de la versión no alineada sigue siendo el predeterminado.

Fer
fuente
Gran solución Lo probé y es perfecto para mi problema. ¡Gracias!
Pabel
¿Es posible utilizar el mismo enfoque en Xamarin Studio?
Alessandro Caliaro
Sería genial si fuera posible, pero ahora estoy comenzando un curso de Xamarin y todavía no tengo suficiente práctica para saber si es posible o no. Haré esta pregunta y vendré aquí de nuevo.
Fer
Comentario del profesor del curso: "hay una opción en la que puede usar comandos para cambiar el nombre de los archivos generados". Por lo tanto, el enfoque para usar desde Xamarin debe ser diferente al que escribí para Android Studio, lo siento.
Fer
3
Para resolver el error No se puede establecer el valor de la propiedad de sólo lectura 'OutputFile' - como se ha mencionado en un comentario anterior de tener que "el cambio eacha ally output.outputFilea outputFileName" - este post proporciona algunos detalles al respecto: stackoverflow.com/a/44265374/2162226
Gene Bo
19

En resumen, para aquellos que no saben cómo importar paquetes build.gradle(como yo), use lo siguiente 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")) 
        }
    }       
}

===== EDITAR =====

Si configura su versionCodey versionNameen su build.gradlearchivo de esta manera:

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

Deberías configurarlo así:

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 con Android Studio 1.0 ======

Si está utilizando Android Studio 1.0, recibirá un error como este:

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

Debería cambiar la build.Typesparte a esto:

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
fuente
Esto funciona muy bien. Sin embargo, dado que incremente mi versión de manifiesto en la compilación de Gradle, creará un APK con el valor anterior (previo al incremento). ¿Alguna forma de asegurarse de que esto surta efecto después de que el script gradle incremente el número de versión?
Guy
1
@ Guy Lo siento, tomó tanto tiempo. Edité la respuesta, vea si puede resolver su problema.
Wesley
17

Si no especifica versionName en el bloque defaultConfig defaultConfig.versionName, el resultado seránull

para obtener versionName del manifiesto, puede escribir el siguiente código en build.gradle:

import com.android.builder.DefaultManifestParser

def manifestParser = new DefaultManifestParser()
println manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
Arkadiusz Konior
fuente
77
Creo que con versiones posteriores de gradle, ahora es com.android.builder.core.DefaultManifestParser
Ryan S
8

En mi caso, solo quería encontrar una manera de automatizar la generación de apknombres releasey debugvariantes diferentes. Logré hacer esto fácilmente poniendo este fragmento como hijo 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 el nuevo complemento de Android Gradle 3.0.0 puede hacer algo así:

 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
    }
}

Esto produce algo como: My_nice_name_3.2.31_dbg.apk

yshahak
fuente
6

Otra alternativa es usar lo siguiente:

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
}

Esto establecerá "appname-1.0.0" en todas sus salidas apk.

Marco RS
fuente
Lo siento no funciona (por más tiempo): No such property: archivesBaseName for class: org.gradle.api.internal.project.DefaultProject_Decorated
Martin
¿Qué versión de gradle estás usando?
Marco RS
6

Gradle 6+

Ahora estoy usando lo siguiente en Android Studio 4.0 y 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

La sintaxis ha cambiado un poco en Gradle 4 (Android Studio 3+) (de output.outputFilea outputFileName, la idea de esta respuesta ahora es:

android {
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def newName = outputFileName
            newName.replace(".apk", "-${variant.versionName}.apk")
            outputFileName = new File(newName)
        }
    }
}
PHPirate
fuente
¿Alguna idea de cómo solucionar esto para gradle 6?
spartygw
@spartygw Actualizó la respuesta
PHPirate
5

La forma correcta de cambiar el nombre de apk, según @Jon answer

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')}"
    }   

O de otra manera puede lograr los mismos resultados con

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
fuente
Agradable en esto! Me gusta más que otras formas en que lo hago actualmente.
Droid Chris
3

Hay muchas respuestas que son correctas, ya sea en su totalidad o después de algunas modificaciones. Pero de todos modos voy a agregar el mío ya que estaba teniendo el problema con todos ellos porque estaba usando scripts para generar VersionName y VersionCode dinámicamente al conectarme alpreBuild tarea.

Si está utilizando un enfoque similar, este es el 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 estoy anulando el código de versión y el nombre en la primera acción de preBuild, tengo que agregar el cambio de nombre del archivo al final de esta tarea. Entonces, lo que hará Gradle en este caso es:

Inyecte el código / nombre de la versión-> realice acciones previas a la creación -> reemplace el nombre para apk

Igor Čordaš
fuente
¿Dónde está configurando las variables generadas versionCode y versionName?
Marte el
Como recuerdo, eso se hizo dentro de nuestro complemento de gradle personalizado. Su ejecución se llamó como última acción de la tarea preBuild.
Igor Čordaš
2
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk")
        }
    }
tiempo en
fuente
Si bien este fragmento de código puede resolver la pregunta, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y que esas personas podrían no conocer los motivos de su sugerencia de código.
Rosário Pereira Fernandes
1

En mi caso resuelvo este error de esta manera

agregando un SUFIJO a la versión de depuración, en este caso agrego el texto "-DEBUG" a mi implementación de depuración

 buildTypes {
        release {

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


        }
        debug {

            defaultConfig {
                debuggable true

                versionNameSuffix "-DEBUG"
            }
        }
    }
exequielc
fuente
Esto no cambia el nombre del archivo APK.
Tom
1
Este es un buen consejo, en realidad. No en la pregunta correcta, pero buena. ¿Dónde puedo leer más al respecto? ¿Es posible usar versionNameSuffixbasado en la rama GIT? Por ejemplo, si no está en "maestro", siempre tenga un sufijo, incluso si es una versión de lanzamiento
desarrollador de Android
0

Para las últimas versiones de gradle puede usar el siguiente fragmento:

Establezca primero la ubicación del manifiesto de la aplicación

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

Y luego en 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 si tiene manifiestos diferentes por tipo de compilación. pero como tengo el único, funciona perfectamente para mí.

Alfishe
fuente
¿Es posible agregar una cadena de un archivo de clase al nombre del apk?
Upendra Shah
0

A partir de Android Studio 1.1.0, encontré que esta combinación funcionaba en el cuerpo de Android del build.gradlearchivo. Esto es si no puede averiguar cómo importar los datos del archivo xml manifiesto. Desearía que fuera más compatible con Android Studio, pero solo juega con los valores hasta que obtengas la salida del nombre apk deseado:

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
fuente