Android Gradle에서 versionCode를 자동 증가시키는 방법


78

Gradle을 기반으로 한 새로운 Android 빌드 시스템을 실험 중이며 versionCode를 자동으로 늘리는 가장 좋은 방법이 무엇인지 생각하고 있습니다. 두 가지 옵션을 생각하고 있습니다

  1. versionCode 파일을 만들고, 번호를 읽고, 늘리고, 파일에 다시 씁니다.
  2. AndroidManifest.xml을 구문 분석하고, 여기에서 versionCode를 읽고, 늘리고, AndroidManifest.xml에 다시 씁니다.

더 간단하거나 적합한 솔루션이 있습니까?

누구든지 멘티 오드 옵션 중 하나를 사용하여 나와 공유 할 수 있습니까?


version.properties파일 에서 읽기 stackoverflow.com/a/21405744
Dori

답변:


58

두 번째 옵션 인 구문 분석을 결정했습니다 AndroidManifest.xml. 다음은 작업 스 니펫입니다.

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

versionCode이 경우 릴리스 빌드 용으로 릴리스됩니다. 디버그 빌드를 위해 그것을 늘리려면 task.whenTaskAdded콜백 에서 task.name 방정식을 변경하십시오 .


5
한 가지 질문, 이러한 코드를 Cradle 빌드 시스템에 통합하는 방법은 무엇입니까?
LiangWang 2014 년

또한, 여기에 다소 청소기의 대답은 장소에 XML을 수정하지만, 소품 파일에 버전 번호를 유지하지 않습니다 stackoverflow.com/questions/21405457/...
폴 캔 트렐

1
새 프로젝트 구조를 사용하는 경우 file ( "AndroidManifest.xml")을 file ( "src / main / AndroidManifest.xml")로 변경하십시오.
Elhanan Mishraky

3
AndroidManifest.xml에 versionCode를 설정하지 않으면 어떻게됩니까?
IgorGanapolsky 2015

@Jacky 그래도 해결 방법이 없으면 내 대답을 참조하십시오. stackoverflow.com/a/39619297/1150251
iStar

39

이 코드를 사용하여 "major.minor.patch.build"체계를 사용하여 versionCode와 versionName을 모두 업데이트합니다.

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
당신은 맨 위에 패턴을 가져 오는 것을 잊었다 : import java.util.regex.Pattern
Mic92

1
나는 이것이 다소 오래되었다는 것을 알고 있지만 물어 보는 것은 아프지 않지만 위의 스 니펫을 사용해 보았습니다.이 오류가 발생했습니다 Error:(48) Execution failed for task ':app:incrementVersionName'. > No match found.
acrichm

1
@acrichm : 메이크업은 반드시 설정 android:versionName="0.0.0.1"경기 수있을 것으로 예상되지 않습니다 다른 매니페스트에
제이 윅

완벽하게 작동하지만 BuildConfig.java에서 versionName은 비어 있습니다. public static final String VERSION_NAME = "";
알 - Mothafar

때문에 느린 것 안드로이드 스튜디오에서 그 "즉시 실행"을 조심Full recompilation is required because 'BuildConfig.java' was changed.
이반 차우

36

사용중인 정확한 설정이 아닌 것 같지만 제 경우에는 빌드가 jenkins에 의해 실행되고 있으며 $ BUILD_NUMBER를 앱의 versionCode로 사용하고 싶었습니다. 다음은 나를 위해 트릭을했습니다.

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

System.genenv는 무엇입니까?
IgorGanapolsky

실제로 Jenkins를 사용할 때 많은 도움이되었습니다. 당신이 사용할 수있는 이 플러그인을 빌드 번호와 environmt 변수를 생성하고 그것을 읽어 System.getenv()Gradle을한다.
Lamorak

19

버전 코드에 타임 스탬프를 사용하고 있습니다.

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

defaultConfig {
    minSdkVersion 10
    targetSdkVersion 21
    versionCode code
}

1
이것은 간단하고 천재적입니다. 엄지 손가락
Євген Гарастович

7

build.gradle 파일에 버전 코드가있는 경우 다음 스 니펫을 사용하세요.

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

해당 패턴이 versionCode와 일치하지 않습니다.
라고스

build.gradle을 게시 할 수 있습니까?
Elhanan Mishraky

내 build.gradle은 일반 빌드 파일입니다. VersionCode 행은 versionCode 18 . 테스터 ( "versionCode \d+") 에서 정규식을 실행하더라도 일치하지 않습니다.
라고스

오류는 공백이 하나 더 있다는 것입니다. Android Studio는 .NET versionCode의 텍스트와 함께 정렬되기 때문에 및 숫자 에 두 개의 공백을 사용 합니다 versionName.
라고스


4

제품 버전과 빌드 유형을 모두 고려하고 매니페스트 구문 분석을위한 @sealskej 논리를 사용하려면 다음을 수행하십시오.

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
어디 우리가 이것을 작성해야 할 ... 내 말은하는 클래스 / 파일이 코드의 요구를 추가 할
ChArAnJiT

이것은 빌드 프로세스의 일부이므로 build.gradle의 일부입니다
Max Ch

3

증분 VersionCode 작업 (정수) :

1예를 들어 다음과 같이 버전 코드를 씩 늘려서 작동합니다 .

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

증분 VersionName 작업 (문자열) :

경고 : 1정규식에 마침표를 포함해야합니다.

0.01예를 들어 버전 이름을으로 증분하면 작동합니다. 증분 을 쉽게 수정 및 변경하거나 숫자를 더 추가 할 수 있습니다.

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

전에:

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

후:

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

당신이 작성하는 경우 versionCode에서의 gradle.build파일 (현재 대부분의 경우), 여기에 해결 방법입니다. 약간 멍청하지만 ( "self"업데이트) 작동합니다!

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

@sealskej의 게시물에 추가하려면 다음과 같이 버전 코드와 버전 이름을 모두 업데이트 할 수 있습니다 (여기에서는 주 버전과 부 버전이 모두 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

이건 어때? build.gradle (앱 모듈)에 추가

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
좋은 생각이지만(20160129 + 000000000) < (20160128 + 125959999)
C0D3LIC1OU5

0

그래서 대부분의 솔루션을 살펴 보았을 때 훌륭했지만 충분하지 않았기 때문에 다중 배포 당 하나의 증분을 작성했습니다.

이렇게하면 디버그 버전을 컴파일 할 때 빌드가 증가하고 배포 할 때 포인트 및 버전 코드가 증가합니다.

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

내 접근 방식은 폴더를 삭제하는 것보다 빌드 폴더에서 매니페스트 파일을 읽고 거기에서 buildVersion을 얻는 것입니다. 작업이 새 매니페스트를 만들 때 증분 된 buildVersion 변수가 이미 있습니다.

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

이것은 질문에 대한 답을 제공하지 않습니다. 충분한 평판얻으면 모든 게시물댓글 수 있습니다 . 대신 질문자의 설명이 필요하지 않은 답변을 제공하세요 . - 검토에서
MLavoie

지금 내 WIP 조각 확인해 @MLavoie
Katoteshi 후쿠
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.