Cómo autoincrementar versionCode en Android Gradle


78

Estoy experimentando con un nuevo sistema de compilación de Android basado en Gradle y estoy pensando, ¿cuál es la mejor manera de aumentar automáticamente versionCode con él? Estoy pensando en dos opciones

  1. crear el archivo versionCode, leer el número de él, aumentarlo y escribirlo de nuevo en el archivo
  2. analizar AndroidManifest.xml, leer versionCode de él, aumentarlo y escribirlo de nuevo en AndroidManifest.xml

¿Existe alguna solución más sencilla o adecuada?

¿Alguien ha usado una de las opciones de mentiod y podría compartirla conmigo?


Leyendo de un version.propertiesarchivo stackoverflow.com/a/21405744
Dori

Respuestas:


58

Me he decidido por la segunda opción: analizar AndroidManifest.xml. Aquí está el fragmento de trabajo.

task('increaseVersionCode') << {
    def manifestFile = file("AndroidManifest.xml")
    def pattern = Pattern.compile("versionCode=\"(\\d+)\"")
    def manifestText = manifestFile.getText()
    def matcher = pattern.matcher(manifestText)
    matcher.find()
    def versionCode = Integer.parseInt(matcher.group(1))
    def manifestContent = matcher.replaceAll("versionCode=\"" + ++versionCode + "\"")
    manifestFile.write(manifestContent)
}

tasks.whenTaskAdded { task ->
    if (task.name == 'generateReleaseBuildConfig') {
        task.dependsOn 'increaseVersionCode'
    }
}

versionCodese lanza para versiones de lanzamiento en este caso. Para aumentarlo para las compilaciones de depuración, cambie la ecuación task.name en la task.whenTaskAddeddevolución de llamada.


5
una pregunta, ¿cómo integrar ese código en el sistema de compilación Cradle?
LiangWang

Además, una respuesta algo más limpia aquí no modifica XML en su lugar, pero mantiene el número de versión en un archivo de accesorios: stackoverflow.com/questions/21405457/…
Paul Cantrell

1
Simplemente cambie el archivo ("AndroidManifest.xml") por el archivo ("src / main / AndroidManifest.xml") si está utilizando la nueva estructura del proyecto.
Elhanan Mishraky

3
¿Qué pasa si no configuro versionCode en mi AndroidManifest.xml?
IgorGanapolsky

@Jacky Si todavía no tienen una solución alternativa, vea mi respuesta: stackoverflow.com/a/39619297/1150251
iStar

39

Estoy usando este código para actualizar tanto versionCode como versionName, usando un esquema "major.minor.patch.build".

import java.util.regex.Pattern

task('increaseVersionCode') << {
    def manifestFile = file("src/main/AndroidManifest.xml")
    def pattern = Pattern.compile("versionCode=\"(\\d+)\"")
    def manifestText = manifestFile.getText()
    def matcher = pattern.matcher(manifestText)
    matcher.find()
    def versionCode = Integer.parseInt(matcher.group(1))
    def manifestContent = matcher.replaceAll("versionCode=\"" + ++versionCode + "\"")
    manifestFile.write(manifestContent)
}

task('incrementVersionName') << {
    def manifestFile = file("src/main/AndroidManifest.xml")
    def patternVersionNumber = Pattern.compile("versionName=\"(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)\"")
    def manifestText = manifestFile.getText()
    def matcherVersionNumber = patternVersionNumber.matcher(manifestText)
    matcherVersionNumber.find()
    def majorVersion = Integer.parseInt(matcherVersionNumber.group(1))
    def minorVersion = Integer.parseInt(matcherVersionNumber.group(2))
    def pointVersion = Integer.parseInt(matcherVersionNumber.group(3))
    def buildVersion = Integer.parseInt(matcherVersionNumber.group(4))
    def mNextVersionName = majorVersion + "." + minorVersion + "." + pointVersion + "." + (buildVersion + 1)
    def manifestContent = matcherVersionNumber.replaceAll("versionName=\"" + mNextVersionName + "\"")
    manifestFile.write(manifestContent)
}

tasks.whenTaskAdded { task ->
    if (task.name == 'generateReleaseBuildConfig' || task.name == 'generateDebugBuildConfig') {
        task.dependsOn 'increaseVersionCode'
        task.dependsOn 'incrementVersionName'
    }
}

1
Olvidó importar el patrón en la parte superior: import java.util.regex.Pattern
Mic92

1
Sé que este es un poco viejo, pero oye, no está de más preguntar, pero intenté usar el fragmento anterior, recibo este error. ¿ Error:(48) Execution failed for task ':app:incrementVersionName'. > No match foundAlguna idea?
acrichm

1
@acrichm: asegúrese de establecer android:versionName="0.0.0.1"en el manifiesto, de lo contrario, no se esperará un número de coincidencias
Jay Wick

Funciona perfectamente, pero en BuildConfig.java versionName está vacío, público estático final String VERSION_NAME = "";
Al-Mothafar

Tenga en cuenta que "Instant Run" en Android Studio sería más lento porqueFull recompilation is required because 'BuildConfig.java' was changed.
Ivan Chau

36

no parece ser la configuración exacta que estás usando, pero en mi caso las compilaciones están siendo ejecutadas por jenkins y quería usar su $ BUILD_NUMBER como el código de versión de la aplicación. lo siguiente hizo el truco para mí allí.

defaultConfig {
    ...
    versionCode System.getenv("BUILD_NUMBER") as Integer ?: 9999
    ...
}

¿Qué es System.genenv?
IgorGanapolsky

En realidad, esto me ayudó mucho al usar Jenkins. Puede usar este complemento para crear una variable de entorno con el número de compilación y leerla System.getenv()en el gradle.
Lamorak

19

Estoy usando la marca de tiempo para el código de versión:

def date = new Date()
def formattedDate = date.format('yyMMddHHmm')
def code = formattedDate.toInteger()

defaultConfig {
    minSdkVersion 10
    targetSdkVersion 21
    versionCode code
}

1
esto es simple y genial. pulgar hacia arriba
Євген Гарастович

7

Si tiene el código de la versión en el archivo build.gradle, use el siguiente fragmento:

import java.util.regex.Pattern    
task('increaseVersionCode') << {
    def buildFile = file("build.gradle")
    def pattern = Pattern.compile("versionCode\\s+(\\d+)")
    def manifestText = buildFile.getText()
    def matcher = pattern.matcher(manifestText)
    matcher.find()
    def versionCode = Integer.parseInt(matcher.group(1))
    def manifestContent = matcher.replaceAll("versionCode " + ++versionCode)
    buildFile.write(manifestContent)
}

Ese patrón no coincide con el versionCode.
lagos

¿Puedes publicar tu build.gradle?
Elhanan Mishraky

Mi build.gradle es un archivo de construcción normal. La línea VersionCode se parece a versionCode 18 . Incluso si ejecuté su expresión regular en un tester ( "versionCode \d+"), no coincidirá.
lagos

El error fue ese espacio en blanco más. Android Studio usa dos espacios en blanco en versionCodey el dígito, ya que se alineará con el texto en versionName.
lagos


4

Para tener en cuenta los sabores de los productos y los tipos de compilación y usar la lógica de @ sealskej para analizar el manifiesto:

android.applicationVariants.all { variant ->
    /* Generate task to increment version code for release */
    if (variant.name.contains("Release")) {
        def incrementVersionCodeTaskName = "increment${variant.name}VersionCode"
        task(incrementVersionCodeTaskName) << {
            if (android.defaultConfig.versionCode == -1) {
                def manifestFile = file(android.sourceSets.main.manifest.srcFile)
                def pattern = Pattern.compile("versionCode=\"(\\d+)\"")
                def manifestText = manifestFile.getText()
                def matcher = pattern.matcher(manifestText)
                matcher.find()
                def versionCode = Integer.parseInt(matcher.group(1))
                android.defaultConfig.versionCode = versionCode + 1
                def manifestContent = matcher.replaceAll("versionCode=\"" + android.defaultConfig.versionCode + "\"")
                manifestFile.write(manifestContent)
            }
        }
        def hookTask = variant.generateBuildConfig
        hookTask.dependsOn(incrementVersionCodeTaskName)
    }
}

1
¿Dónde necesitamos escribir esto ... quiero decir en qué clase / archivo se debe agregar este código?
ChArAnJiT

esto es parte de build.gradle ya que es parte del proceso de construcción
Max Ch

3

Incrementar la tarea de código de versión (entero):

Esto funciona incrementando el código de versión 1, por ejemplo:

  android:versionCode="1"
1 + 1 = 2
import java.util.regex.Pattern

task incrementVersionCode << {
    def manifestFile = file('AndroidManifest.xml')
    def matcher = Pattern.compile('versionCode=\"(\\d+)\"')
    .matcher(manifestFile.getText())
    matcher.find()
    def manifestContent = matcher.replaceAll('versionCode=\"' +
        ++Integer.parseInt(matcher.group(1)) + '\"')
    manifestFile.write(manifestContent)
}

Incrementar la tarea de VersionName (cadena):

Advertencia: debe contener un 1período para Regex

Esto funciona incrementando el Nombre de la versión 0.01, por ejemplo: Puede modificar y cambiar fácilmente su incremento o agregar más dígitos.

android:versionName="1.0"
1.00 + 0.01 -> 1.01
1.01 + 0.01 -> 1.02
1.10 + 0.01 -> 1.11
1.99 + 0.01 -> 2.0
1.90 + 0.01 -> 1.91
import java.util.regex.Pattern

task incrementVersionName << {
    def manifestFile = file('AndroidManifest.xml')
    def matcher = Pattern.compile('versionName=\"(\\d+)\\.(\\d+)\"')
    .matcher(manifestFile.getText())
    matcher.find()
    def versionName = String.format("%.2f", Integer
        .parseInt(matcher.group(1)) + Double.parseDouble("." + matcher
            .group(2)) + 0.01)
    def manifestContent = matcher.replaceAll('versionName=\"' +
        versionName + '\"')
    manifestFile.write(manifestContent)
}

Antes de:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.exmaple.test"
    android:installLocation="auto"
    android:versionCode="1"
    android:versionName="1.0" >

Después:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.exmaple.test"
    android:installLocation="auto"
    android:versionCode="2"
    android:versionName="1.01" >

3

Si escribe su archivo versionCodein gradle.build(la mayoría de los casos actualmente), aquí hay una solución. Un poco estúpido (actualizar "self"), ¡pero funciona!

import java.util.regex.Pattern

task('increaseVersionCode') << {
    def buildFile = file("build.gradle")
    def pattern = Pattern.compile("versionCode(\\s+\\d+)")
    def buildText = buildFile.getText()
    def matcher = pattern.matcher(buildText)
    matcher.find()
    def versionCode = android.defaultConfig.versionCode
    def buildContent = matcher.replaceAll("versionCode " + ++versionCode)
    buildFile.write(buildContent)

    System.out.println("Incrementing Version Code ===> " + versionCode)
}

tasks.whenTaskAdded { task ->
    if (task.name == 'generateReleaseBuildConfig') {
        task.dependsOn 'increaseVersionCode'
    }
}

2

Para agregar a la publicación de @ sealskej, así es como puede actualizar tanto el código de su versión como el nombre de la versión (aquí supongo que su versión principal y secundaria son ambas 0):

task('increaseVersion') << {
    def manifestFile = file("AndroidManifest.xml")
    def patternVersionCode = Pattern.compile("versionCode=\"(\\d+)\"")
    def manifestText = manifestFile.getText()
    def matcherVersionCode = patternVersionCode.matcher(manifestText)
    matcherVersionCode.find()
    def versionCode = Integer.parseInt(matcherVersionCode.group(1))
    def manifestContent = matcherVersionCode.replaceAll("versionCode=\"" + ++versionCode + "\"")

    manifestFile.write(manifestContent)

    def patternVersionNumber = Pattern.compile("versionName=\"0.0.(\\d+)\"")
    manifestText = manifestFile.getText()
    def matcherVersionNumber = patternVersionNumber.matcher(manifestText)
    matcherVersionNumber.find()
    def versionNumber = Integer.parseInt(matcherVersionNumber.group(1))
    manifestContent = matcherVersionNumber.replaceAll("versionName=\"0.0." + ++versionNumber + "\"")
    manifestFile.write(manifestContent)
}

1

que hay de esto agregar a build.gradle (módulo de la aplicación)

def getBuildVersionCode() {
    def date = new Date()
    def formattedDate = date.format('yyyyMMdd')
    def formattedSeconds = date.format('HHmmssSSS')
    def formatInt = formattedDate as int;
    def SecondsInt = formattedSeconds as int;
    return (formatInt + SecondsInt) as int
}

   defaultConfig {
    applicationId "com.app"
    minSdkVersion 17
    targetSdkVersion 22
    versionCode getBuildVersionCode()
    versionName "1.0"
}

2
Gran pensamiento, sino(20160129 + 000000000) < (20160128 + 125959999)
C0D3LIC1OU5

0

Entonces, mientras buscaba la mayor parte de la solución, eran agradables pero no lo suficiente, así que escribí esto, un incremento por implementación múltiple:

Esto incrementará la compilación al compilar versiones de depuración e incrementará el punto y el código de versión al implementar.

import java.util.regex.Pattern

def incrementVersionName(int length, int index) {
    def gradleFile = file("build.gradle")
    def versionNamePattern = Pattern.compile("versionName\\s*\"(.*?)\"")
    def gradleText = gradleFile.getText()
    def matcher = versionNamePattern.matcher(gradleText)
    matcher.find()

    def originalVersion = matcher.group(1)
    def originalVersionArray = originalVersion.split("\\.")
    def versionKeys = [0, 0, 0, 0]
    for (int i = 0; i < originalVersionArray.length; i++) {
        versionKeys[i] = Integer.parseInt(originalVersionArray[i])
    }
    def finalVersion = ""
    versionKeys[index]++;
    for (int i = 0; i < length; i++) {
        finalVersion += "" + versionKeys[i]
        if (i < length - 1)
            finalVersion += "."
    }

    System.out.println("Incrementing Version Name: " + originalVersion + " ==> " + finalVersion)

    def newGradleContent = gradleText.replaceAll("versionName\\s*\"(.*?)\"", "versionName \"" + finalVersion + "\"")
    gradleFile.write(newGradleContent)
}

def incrementVersionCode() {
    def gradleFile = file("build.gradle")
    def versionCodePattern = Pattern.compile("versionCode\\s*(\\d+)")
    def gradleText = gradleFile.getText()
    def matcher = versionCodePattern.matcher(gradleText)
    matcher.find()

    def originalVersionCode = Integer.parseInt(matcher.group(1) + "")
    def finalVersionCode = originalVersionCode + 1;
    System.out.println("Incrementing Version Code: " + originalVersionCode + " ==> " + finalVersionCode)

    def newGradleContent = gradleText.replaceAll("versionCode\\s*(\\d+)", "versionCode " + finalVersionCode)
    gradleFile.write(newGradleContent)
}

task('incrementVersionNameBuild') << {
    incrementVersionName(4, 3)
}

task('incrementVersionNamePoint') << {
    incrementVersionName(3, 2)
}

task('incrementVersionCode') << {
    incrementVersionCode()
}


def incrementedBuild = false
def incrementedRelease = false

tasks.whenTaskAdded { task ->
    System.out.println("incrementedRelease: " + incrementedRelease)
    System.out.println("incrementedBuild: " + incrementedBuild)
    System.out.println("task.name: " + task.name)

    if (!incrementedBuild && task.name.matches('generate.*?DebugBuildConfig')) {
        task.dependsOn 'incrementVersionNameBuild'
        incrementedBuild = true
        return
    }

    if (!incrementedRelease && task.name.matches('generate.*?ReleaseBuildConfig')) {
        task.dependsOn 'incrementVersionCode'
        task.dependsOn 'incrementVersionNamePoint'
        incrementedRelease = true
        return
    }
}

-1

Mi enfoque es leer el archivo de manifiesto de la carpeta de compilación y sacar buildVersion de allí, luego borrar una carpeta. Cuando la tarea crea un nuevo manifiesto, mi variable buildVersion incrementada ya está allí.

def versionPattern = "Implementation-Version=(\\d+.\\d+.\\d+.\\d+\\w+)"

task generateVersion (dependsOn : 'start') {
    // read build version from previous manifest
    def file = file("build/libs/MANIFEST.MF")
    if (file.exists()) {
        def pattern = Pattern.compile(versionPattern)
        def text = file.getText()
        def matcher = pattern.matcher(text)
        matcher.find()
        buildNumber = Integer.parseInt(matcher.group(1))
        // increment build version
        version = "${majorVer}.${minorVer}.${patchVer}.${++buildNumber}${classifier}_${access}"
    } 
    else 
        version = "${majorVer}.${minorVer}.${patchVer}.1${classifier}_${access}"
}

task specifyOutputDir (dependsOn : 'generateVersion', type : JavaCompile) {
    // create a folder for new build
    destinationDir = file("build/${version}/")
}

task clean (dependsOn : 'generateVersion', type : Delete) {
    doLast {
        delete "build/${version}"
        println 'Build directory is deleted'
    }
}

task configureJar (dependsOn : 'generateVersion', type : Jar) {
    baseName = applicationName
    version = project.version
    archiveName = "${applicationName}_ver${version}.${extension}"
    manifest {[
            "Main-Class" : mainClassName,
            "Implementation-Title" : name,
            "Implementation-Version" : version,
            "Access" : access,
            "Developer" : developer
    ]}
}

Esto no proporciona una respuesta a la pregunta. Una vez que tenga suficiente reputación , podrá comentar en cualquier publicación ; en su lugar, proporcione respuestas que no requieran aclaración por parte del autor de la pregunta . - De la crítica
MLavoie

@MLavoie compruébalo ahora mi fragmento de WIP
Katoteshi Fuku
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.