So erhöhen Sie den versionCode in Android Gradle automatisch

78

Ich experimentiere mit einem neuen Android-Build-System, das auf Gradle basiert, und überlege, wie ich den Versionscode am besten automatisch erhöhen kann. Ich denke über zwei Optionen nach

  1. Erstellen Sie eine versionCode-Datei, lesen Sie die Nummer daraus, erhöhen Sie sie und schreiben Sie sie zurück in die Datei
  2. Analysieren Sie AndroidManifest.xml, lesen Sie den versionCode daraus, erhöhen Sie ihn und schreiben Sie ihn zurück in die AndroidManifest.xml

Gibt es eine einfachere oder geeignetere Lösung?

Hat jemand eine der Mentiod-Optionen verwendet und könnte sie mit mir teilen?

Sealskej
quelle
Lesen aus einer version.propertiesDatei stackoverflow.com/a/21405744
Dori

Antworten:

57

Ich habe mich für die zweite Option entschieden - das Parsen AndroidManifest.xml. Hier arbeitet ein Ausschnitt.

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

versionCodewird in diesem Fall für Release-Builds freigegeben. Um es für Debug-Builds zu erhöhen, ändern Sie die task.name-Gleichung im task.whenTaskAddedRückruf.

Sealskej
quelle
5
Eine Frage: Wie kann dieser Code in das Cradle-Build-System integriert werden?
LiangWang
Auch eine etwas sauberere Antwort hier ändert XML nicht an Ort und Stelle, sondern behält die Versionsnummer in einer Requisitendatei: stackoverflow.com/questions/21405457/…
Paul Cantrell
1
Ändern Sie einfach die Datei ("AndroidManifest.xml") in die Datei ("src / main / AndroidManifest.xml"), wenn Sie die neue Projektstruktur verwenden.
Elhanan Mishraky
3
Was ist, wenn ich versionCode nicht in meiner AndroidManifest.xml einstelle?
IgorGanapolsky
@ Jacky Wenn ihr noch keine Problemumgehung habt, siehe meine Antwort: stackoverflow.com/a/39619297/1150251
iStar
39

Ich verwende diesen Code, um sowohl versionCode als auch versionName mithilfe eines Schemas "major.minor.patch.build" zu aktualisieren.

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'
    }
}
Andres
quelle
1
Sie haben vergessen, Muster oben zu importieren: import java.util.regex.Pattern
Mic92
1
Ich weiß, dass dieser ein bisschen alt ist, aber hey, es tut nicht weh zu fragen, aber ich habe versucht, das obige Snippet zu verwenden. Ich bekomme diesen Fehler Error:(48) Execution failed for task ':app:incrementVersionName'. > No match foundirgendwelche Ideen?
Akrichm
1
@acrichm: Stellen Sie sicher, dass Sie android:versionName="0.0.0.1"im Manifest festlegen, dass sonst keine Anzahl von Spielen erwartet wird
Jay Wick,
Es funktioniert perfekt, aber in BuildConfig.java ist versionName leer, public static final String VERSION_NAME = "";
Al-Mothafar
Beachten Sie, dass "Instant Run" in Android Studio langsamer wäre, weilFull recompilation is required because 'BuildConfig.java' was changed.
Ivan Chau
36

Es scheint nicht das genaue Setup zu sein, das Sie verwenden, aber in meinem Fall werden die Builds von Jenkins ausgeführt und ich wollte $ BUILD_NUMBER als Versionscode der App verwenden. Das Folgende hat den Trick für mich dort gemacht.

defaultConfig {
    ...
    versionCode System.getenv("BUILD_NUMBER") as Integer ?: 9999
    ...
}
user2399268
quelle
Was ist System.genenv?
IgorGanapolsky
Das hat mir bei der Verwendung von Jenkins sehr geholfen. Mit diesem Plugin können Sie Umgebungsvariablen mit Build-Nummer erstellen und System.getenv()im Gradle lesen.
Lamorak
18

Ich verwende einen Zeitstempel für den Versionscode:

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

defaultConfig {
    minSdkVersion 10
    targetSdkVersion 21
    versionCode code
}
thanhbinh84
quelle
1
Das ist einfach und genial. Daumen hoch
Євген Гарастович
7

Wenn Sie den Versionscode in der Datei build.gradle halten, verwenden Sie das nächste Snippet:

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)
}
Elhanan Mishraky
quelle
Dieses Muster stimmt nicht mit dem versionCode überein.
Lagos
Kannst du dein build.gradle posten?
Elhanan Mishraky
Mein build.gradle ist eine normale Build-Datei. Die VersionCode-Zeile sieht aus wie versionCode 18 . Selbst wenn ich Ihren regulären Ausdruck auf einem Tester ( "versionCode \d+") ausgeführt habe, stimmt er nicht überein.
Lagos
Der Fehler war, dass noch ein Leerzeichen. Android Studio verwendet zwei Leerzeichen versionCodeund die Ziffer, da diese zusammen mit dem Text in ausgerichtet werden versionName.
Lagos
5

Gradle Erweiterte Build - Version ist ein Plugin für Android , das macht Erzeugung version und version automatisch. Es gibt viele Anpassungen. Hier finden Sie weitere Informationen dazu https://github.com/moallemi/gradle-advanced-build-version

Moallemi
quelle
Hinweis: Dies unterstützt noch nicht die automatische Inkrementierung des Versionsnamens
hooby3dfx
4

So berücksichtigen Sie sowohl Produktaromen als auch Build-Typen und verwenden die Logik von @ sealskej zum Parsen von Manifesten:

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)
    }
}
Max Ch
quelle
1
Wo müssen wir das schreiben ... Ich meine, in welcher Klasse / Datei dieser Code hinzugefügt werden muss
ChArAnJiT
Dies ist Teil von build.gradle, da dies Teil des Build-Prozesses ist
Max Ch
3

Inkrementieren Sie die VersionCode-Aufgabe (Ganzzahl):

Dies funktioniert durch Inkrementieren des Versionscodes 1um beispielsweise:

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

Inkrementiere VersionName Task (String):

Warnung: Muss einen 1Punkt für Regex enthalten

Dies funktioniert durch Inkrementieren des Versionsnamens 0.01um beispielsweise: Sie können Ihr Inkrement einfach ändern und weitere Ziffern hinzufügen.

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

Vor:

<?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" >

Nach:

<?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" >
Jared Burrows
quelle
3

Wenn Sie Ihre versionCodeIn- gradle.buildDatei schreiben (meistens derzeit), finden Sie hier eine Problemumgehung. Ein bisschen dumm (Update "self"), aber es funktioniert!

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'
    }
}
iStar
quelle
2

Um den Beitrag von @ sealskej zu ergänzen, können Sie auf diese Weise sowohl Ihren Versionscode als auch Ihren Versionsnamen aktualisieren (hier gehe ich davon aus, dass Ihre Haupt- und Nebenversion beide 0 sind):

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)
}
Karim Varela
quelle
1

was ist damit? zu build.gradle hinzufügen (App-Modul)

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"
}
Karoly
quelle
2
Toller Gedanke, aber(20160129 + 000000000) < (20160128 + 125959999)
C0D3LIC1OU5
0

Da ich mir die meisten Lösungen angesehen habe, waren sie nett, aber nicht genug. Deshalb habe ich dies geschrieben, ein Inkrement pro Multi-Deployment:

Dadurch wird der Build beim Kompilieren von Debug-Versionen und der Punkt und der Versionscode bei der Bereitstellung erhöht.

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
    }
}
TacB0sS
quelle
-1

Mein Ansatz ist es, die Manifestdatei aus dem Build-Ordner zu lesen und buildVersion herauszuholen, bevor ich einen Ordner lösche. Wenn die Aufgabe ein neues Manifest erstellt, ist meine inkrementierte buildVersion-Variable bereits vorhanden.

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
    ]}
}
Katoteshi Fuku
quelle
Dies gibt keine Antwort auf die Frage. Sobald Sie einen ausreichenden Ruf haben, können Sie jeden Beitrag kommentieren . Geben Sie stattdessen Antworten, die nicht vom Fragesteller geklärt werden müssen . - Von der Überprüfung
MLavoie
@ MLavoie check it out jetzt mein WIP-Snippet
Katoteshi Fuku