如何使用Gradle脚本在Android Studio中自动增加和发布已签名的apk

How to automatically increase and release signed apk in Android Studio using Gradle script

我正在尝试自动更新 Android Manifest 中的 versionName 和 VersionCode 参数,并在输出文件名中使用它们而不是 "app-release.apk"。

来自 this site 我在我的 build.gradle 文件中添加了这段代码:

import java.util.regex.Pattern
import com.android.builder.core.DefaultManifestParser

def mVersionCode
def mNextVersionName
def newName

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()
    mVersionCode = Integer.parseInt(matcher.group(1))
    def manifestContent = matcher.replaceAll("versionCode=\"" + ++mVersionCode + "\"")
    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))
    mNextVersionName = majorVersion + "." + minorVersion + "." + pointVersion + "." + (buildVersion + 1)
    def manifestContent = matcherVersionNumber.replaceAll("versionName=\"" + mNextVersionName + "\"")
    manifestFile.write(manifestContent)

}

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

此代码完美运行,2 个任务 运行 并正确更新清单文件。 现在我想在 buildTypes 内的 release 块中使用 2 个变量 mVersionCodemNextVersionName,如下所示:

newName = defaultConfig.applicationId + "-" + mNextVersionName + " (" + mVersionCode + ").apk"
applicationVariants.all { variant ->
                variant.outputs.each {output ->
                    def file = output.outputFile
                    output.outputFile = new File(file.parent, file.name.replace("app-release.apk", newName))
                }
            }

但是2的返回值为空

我也试过设置属性和额外属性:

task.setProperty("vName", mNextVersionName) 
ext.vName = mNextVersionName 
extensions.extraProperties.set("vName", mNextVersionName)

在 2 个任务中,并且运气不佳将它们放在 release 块中。

有人知道如何实现这个吗?

没有人回答,但我找到了一个可行的解决方案。我不喜欢它,它可以用更好的方式完成,但现在是我找到的唯一解决方法。

我仍在寻找更好的解决方案,如果你有,我会很乐意阅读并使用它而不是我的。


所以,我在 gradle.build 文件中添加了一个新任务,它只是复制 'app-release.apk' 文件并使用清单文件中的值重命名它:

task copia{
    dependsOn('assembleRelease')
    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 mVersionName = majorVersion + "." + minorVersion + "." + pointVersion + "." + (buildVersion)

    def pattern = Pattern.compile("versionCode=\"(\d+)\"")
    def matcher = pattern.matcher(manifestText)
    matcher.find()
    def myVersionCode = Integer.parseInt(matcher.group(1))
    copy {
        from 'app-release.apk'
        rename { String fileName ->
            fileName.replace('app-release.apk', 'com.walker93.catpadova-' + mVersionName + ' (' + myVersionCode + ').apk')
        }
        into 'apk_outputs'
    }
}

如您所见,它只是前 2 个任务中代码的复制和编辑版本,带有 copy {} 函数(此处为 docs),它读取 versionName 和 versionCode 值而不用递增它们,然后将它们放入我要替换的新文件名中。

此任务还需要其他 2 个任务,所以最终您将有 3 个任务。 在这个任务的第一行有dependsOn(assembleRelease)。这非常重要,它将 运行 所有其他默认发布构建任务(包括我们在清单中递增和写入的 2 个任务)生成更新和签名的 apk。

现在,如果您尝试 运行 "generate signed APK...",您会注意到此任务不会 运行。相反,您必须手动启动它:

当您想使用自定义名称发布已签名的 apk 时,在 "run configurations" 中添加您的任务,例如 this and then you should be able to run the task from here or here。如果你想生成一个带有默认名称的签名 apk(并且仍然增加 versionName 和 versionCode),只需像以前一样使用 "generate signed APK..." 选项。

使用此方法无需在文件的 buildTypes 部分添加代码。

要使用额外的属性扩展,您需要像这样定义它们:

ext {
  mVersionCode = 0
  mNextVersionName = ""
}

然后您就可以在您的构建脚本中自由访问它们,只需完全按照您在上述任务中使用它们的方式使用它们。

好的,这是我的 build.gradle 应用程序模块的代码:

apply plugin: 'com.android.application'

apply from: 'versionalization.gradle'

def genVersionName = VersionInfo.versionName
def genVersionCode = VersionInfo.versionCode

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "com.vincestyling.exerciseapk"
        minSdkVersion 10
        targetSdkVersion 22
        versionName genVersionName
        versionCode genVersionCode
    }
}

android.applicationVariants.all { variant ->
    def taskSuffix = variant.name.capitalize()
    def assembleTaskName = "assemble${taskSuffix}"

    if (tasks.findByName(assembleTaskName)) {
        def processAPKTask = tasks.create(name: "process${taskSuffix}Apk", type: Copy) {
            variant.outputs.each { output ->
                from output.outputFile
                into output.outputFile.parent

                def newApkName = android.defaultConfig.applicationId + "-" + variant.buildType.name + "-" + genVersionName + " (" + genVersionCode + ").apk"
                rename ~/(.+)/, newApkName
            }
        }
        tasks[assembleTaskName].finalizedBy processAPKTask
    }
}

在head处应用的versionalization.gradle是我用来增加VersionInfo,然后return两个值来使用。

task VersionInfo {
    String FACTOR_KEY = "BUILD_NUMBER_FACTOR"

    File buildDir = file("build")
    buildDir.mkdir()

    File factorPropFile = new File(buildDir, "kbuildfactor.prop")

    Properties props = new Properties()
    if (factorPropFile.exists()) {
        props.load(new FileInputStream(factorPropFile))
    }

    int buildNumberFactor = props.get(FACTOR_KEY) as Integer ?: 0
    buildNumberFactor += 1

    props.put(FACTOR_KEY, buildNumberFactor as String)
    props.store(new FileOutputStream(factorPropFile), null)



    String BASE_VERSION_NAME = "BASE_VERSION_NAME"
    String BASE_VERSION_CODE = "BASE_VERSION_CODE"


    File versionPropFile = file("versioning.properties")
    props.load(new FileInputStream(versionPropFile))


    String baseVersionName = props.get(BASE_VERSION_NAME) as String
    Integer baseVersionCode = props.get(BASE_VERSION_CODE) as Integer

    ext.versionName = baseVersionName + "." + buildNumberFactor
    ext.versionCode = baseVersionCode * 1000 + buildNumberFactor
}

非常简单,阅读两个文件以获取构建版本信息所需的字段。

我们终于 copy/rename 最终的 APK。

此外,copy/rename部分我是先实现的,但是如果你有任何产品口味就不行了,我贴在这里作为另一种选择。

android.applicationVariants.all { variant ->
    variant.outputs.each {output ->
        def newApkName = android.defaultConfig.applicationId + "-" + variant.buildType.name + "-" + genVersionName + " (" + genVersionCode + ").apk"

        def oldApkName = "app-${variant.buildType.name}.apk"

        def file = output.outputFile

        output.outputFile = new File(file.parent, file.name.replace(oldApkName, newApkName))
    }
}