【问题标题】:How to autoincrement versionCode in Android Gradle如何在 Android Gradle 中自动增加 versionCode
【发布时间】:2013-07-01 04:14:49
【问题描述】:

我正在试验基于 Gradle 的新 Android 构建系统,我在想,用它自动增加 versionCode 的最佳方法是什么。我正在考虑两种选择

  1. 创建 versionCode 文件,从中读取编号,增加并写回文件
  2. 解析AndroidManifest.xml,从中读取versionCode,增加并写回AndroidManifest.xml

还有更简单或更合适的解决方案吗?

有没有人使用过上面提到的选项之一并可以与我分享?

【问题讨论】:

标签: android build android-manifest gradle auto-increment


【解决方案1】:

我已决定第二个选项 - 解析 AndroidManifest.xml。这是工作的sn-p。

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方程。

【讨论】:

  • 一个问题,如何将这些代码集成到Cradle构建系统中?
  • 另外,这里更简洁的答案不会修改 XML,而是将版本号保留在 props 文件中:stackoverflow.com/questions/21405457/…
  • 如果您使用的是新的项目结构,只需将 file("AndroidManifest.xml") 更改为 file("src/main/AndroidManifest.xml")。
  • 如果我没有在我的 AndroidManifest.xml 中设置 versionCode 怎么办?
  • @Jacky 如果你们仍然没有解决方法,请参阅我的回答:stackoverflow.com/a/39619297/1150251
【解决方案2】:

我正在使用此代码更新 versionCode 和 versionName,使用“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'
    }
}

【讨论】:

  • 您忘记在顶部导入 Pattern:import java.util.regex.Pattern
  • 我知道这个有点旧了,但是问一下也无妨,但是我尝试使用上面的 sn-p,我收到了这个错误Error:(48) Execution failed for task ':app:incrementVersionName'. &gt; No match found 有什么想法吗?
  • @acrichm: 确保在清单中设置android:versionName="0.0.0.1" 否则不会有预期的匹配数量
  • 它工作正常,但在 BuildConfig.java 中 versionName 为空,public static final String VERSION_NAME = "";
  • 请注意,Android Studio 中的“即时运行”会更慢,因为Full recompilation is required because 'BuildConfig.java' was changed.
【解决方案3】:

这似乎不是您使用的确切设置,但在我的情况下,构建是由 jenkins 运行的,我想使用它的 $BUILD_NUMBER 作为应用程序的版本代码。以下为我做了诀窍。

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

【讨论】:

  • 什么是 System.genenv?
  • 这实际上对我使用 Jenkins 帮助很大。您可以使用此 this plugin 创建具有内部版本号的环境变量,并在 gradle 中使用 System.getenv() 读取它。
【解决方案4】:

更新

作为谷歌玩warning:

Google Play 允许 versionCode 的最大值为 2100000000。

我们可能会更改以下格式以降低达到限制的风险:

def formattedDate = date.format('yyMMddHH')

原创

我正在为版本代码使用时间戳:

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

defaultConfig {
    minSdkVersion 10
    targetSdkVersion 21
    versionCode code
}

【讨论】:

  • 这很简单,也很天才。竖起大拇指
  • 不要这样做!您将使您的版本代码变成一个非常大的数字,并开始从 google play 商店收到错误,指出您已接近允许的最大版本代码。如果您达到该值,您将无法再更新您的应用。
  • @JamesParker 允许的最大版本代码是多少?
  • 很遗憾,如果您使用的是旧格式,那您就倒霉了。
【解决方案5】:

如果您在 build.gradle 文件中保存版本代码,请使用下一个 sn-p:

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 吗?
  • 我的 build.gradle 是一个普通的构建文件。 VersionCode 行看起来像 versionCode 18 。即使我在测试仪 ("versionCode \d+") 上运行您的正则表达式,它也不会匹配。
  • 错误是多了一个空格。 Android Studio 在versionCode 和数字上使用两个空格,因为它将与versionName 中的文本对齐。
【解决方案6】:

Gradle Advanced Build Version 是一个用于自动生成 versionCodeversionName 的 Android 插件。有很多定制。在这里你可以找到更多关于它的信息 https://github.com/moallemi/gradle-advanced-build-version

【讨论】:

  • 注意:目前还不支持版本名自增
【解决方案7】:

考虑产品风格和构建类型并使用@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)
    }
}

【讨论】:

  • 我们需要在哪里写这个......我的意思是这个代码需要添加到哪个类/文件中
  • 这是 build.gradle 的一部分,因为这是构建过程的一部分
【解决方案8】:

递增版本代码任务(整数):

这可以通过将版本代码增加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)
}

递增版本名称任务(字符串):

警告:Regex 必须包含 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" >

【讨论】:

    【解决方案9】:

    如果您将versionCode 写入gradle.build 文件(目前大多数情况下),这里有一个解决方法。有点愚蠢(更新“自我”),但它有效!

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

    【讨论】:

      【解决方案10】:

      要添加到@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)
      }
      

      【讨论】:

        【解决方案11】:

        这个呢? 添加到 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"
        }
        

        【讨论】:

        • 好主意,但(20160129 + 000000000) &lt; (20160128 + 125959999)
        【解决方案12】:

        所以当我研究大多数解决方案时,它们都很好但还不够,所以我写了这个,每次多部署一个增量:

        这将在编译调试版本时增加构建,并在部署时增加点和版本代码。

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

        【讨论】:

          【解决方案13】:

          我的方法是从构建文件夹中读取清单文件并从中获取 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
              ]}
          }
          

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-08-26
          • 1970-01-01
          • 2021-02-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-20
          相关资源
          最近更新 更多