如何使用 Gradle 更改为 App Bundle 生成的文件名?

How to change the generated filename for App Bundles with Gradle?

所以要更改 gradle android 中生成的 APK 文件名,我可以这样做:

applicationVariants.output.all {
    outputFileName = "the_file_name_that_i_want.apk"
}

生成的App Bundle文件有没有类似的东西?如何更改生成的 App Bundle 文件名?

你可以使用这样的东西:

defaultConfig {
  applicationId "com.test.app"
  versionCode 1
  versionName "1.0"
  setProperty("archivesBaseName", applicationId + "-v" + versionCode + "(" + versionName + ")")
}

现在我已经为跨平台 CLI 执行编写了某种 Exec 模板,无论 commandLine 是什么。我的 RenameTask 可以检测 Linux & Windows,以及 release & debug.

属性 archivesBaseName需要定义在defaultConfig:

android {
    defaultConfig {
        setProperty("archivesBaseName", "SomeApp_" + "1.0.0")
    }
}

RenameTask extends Exec 执行重命名(不要与 type: Rename 混淆):

import javax.inject.Inject

/**
 * App Bundle RenameTask
 * @author Martin Zeitler
**/
class RenameTask extends Exec {
    private String buildType
    @Inject RenameTask(String value) {this.setBuildType(value)}
    @Input String getBuildType() {return this.buildType}
    void setBuildType(String value) {this.buildType = value}
    @Override
    @TaskAction
    void exec() {
        def baseName = getProject().getProperty('archivesBaseName')
        def basePath = getProject().getProjectDir().getAbsolutePath()
        def bundlePath = "${basePath}/build/outputs/bundle/${this.getBuildType()}"
        def srcFile = "${bundlePath}/${baseName}-${this.getBuildType()}.aab"
        def dstFile = "${bundlePath}/${baseName}.aab"
        def os = org.gradle.internal.os.OperatingSystem.current()
        if (os.isUnix() || os.isLinux() || os.isMacOsX()) {
            commandLine "mv -v ${srcFile} ${dstFile}".split(" ")
        } else if (os.isWindows()) {
            commandLine "ren ${srcFile} ${dstFile}".split(" ")
        } else {
            throw new GradleException("Cannot move AAB with ${os.getName()}.")
        }
        super.exec()
    }
}

它完成了另外两个任务:

// it defines tasks :renameBundleRelease & :renameBundleDebug
task renameBundleRelease(type: RenameTask, constructorArgs: ['release'])
task renameBundleDebug(type: RenameTask, constructorArgs: ['debug'])

// it sets finalizedBy for :bundleRelease & :bundleDebug
tasks.whenTaskAdded { task ->
    switch (task.name) {
        case 'bundleRelease': task.finalizedBy renameBundleRelease; break
        case   'bundleDebug': task.finalizedBy renameBundleDebug; break
    }
}

先进之处在于,它不会留下任何东西,并且可以将文件移动到任何需要的地方。

作为 的更通用方法,以下内容将侦听添加的任务,然后为添加的任何 bundle* 任务插入重命名任务。

只需将其添加到 build.gradle 文件的底部即可。

Note: It will add more tasks than necessary, but those tasks will be skipped since they don't match any folder. e.g. > Task :app:renameBundleDevelopmentDebugResourcesAab NO-SOURCE

tasks.whenTaskAdded { task ->
    if (task.name.startsWith("bundle")) {
        def renameTaskName = "rename${task.name.capitalize()}Aab"
        def flavor = task.name.substring("bundle".length()).uncapitalize()
        tasks.create(renameTaskName, Copy) {
            def path = "${buildDir}/outputs/bundle/${flavor}/"
            from(path)
            include "app.aab"
            destinationDir file("${buildDir}/outputs/renamedBundle/")
            rename "app.aab", "${flavor}.aab"
        }

        task.finalizedBy(renameTaskName)
    }
}

我发现了一个更好的选项,可以在您生成 apk / aab 时自动增加您的应用程序版本并自动重命名。解决方案如下(记得在你的根文件夹中创建 "version.properties" 文件:

android {
     ...
     ...
    Properties versionProps = new Properties()
    def versionPropsFile = file("${project.rootDir}/version.properties")
    versionProps.load(new FileInputStream(versionPropsFile))
    def value = 0
    def runTasks = gradle.startParameter.taskNames
    if ('assemble' in runTasks || 'assembleRelease' in runTasks) {
        value = 1
    }
    def versionMajor = 1
    def versionPatch = versionProps['VERSION_PATCH'].toInteger() + value
    def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
    def versionNumber = versionProps['VERSION_NUMBER'].toInteger() + value
    versionProps['VERSION_PATCH'] = versionPatch.toString()
    versionProps['VERSION_BUILD'] = versionBuild.toString()
    versionProps['VERSION_NUMBER'] = versionNumber.toString()
    versionProps.store(versionPropsFile.newWriter(), null)

    defaultConfig {
    applicationId "com.your.applicationname"
    versionCode versionNumber
    versionName "${versionMajor}.${versionPatch}.${versionBuild}(${versionNumber})"
    archivesBaseName = versionName
    minSdkVersion 26
    targetSdkVersion 29
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    signingConfig signingConfigs.release
    setProperty("archivesBaseName","${applicationId}-v${versionName}")

    ...
}

感谢 this website and this post

来自 @SaXXuM 的解决方案非常有效!重命名工件不需要任务。您可以直接在 android {} 块中调用 setProperty()。我更喜欢在文件名中包含:

  • 应用程序 ID
  • 模块名称
  • 版本名称
  • 版本号
  • 日期
  • 构建类型

这就是我在我的项目中使用它的方式:

build.gradle:

apply from: "../utils.gradle"

android {
    ...
    setProperty("archivesBaseName", getArtifactName(defaultConfig))
}

utils.gradle:

ext.getArtifactName = {
    defaultConfig ->
        def date = new Date().format("yyyyMMdd")
        return defaultConfig.applicationId + "-" + project.name + "-" + defaultConfig.versionName + "-" + defaultConfig.versionCode + "-" + date
}

结果是:

com.example-app-1.2.0-10200000-20191206-release.aab

它适用于 APK 和 AAB。

根据 Martin Zeitler 的回答,我在 Windows:

上做了这个

请注意,在我的设置中,.aab 文件是在发布文件夹中创建的,它会按照 bug report.

删除该文件夹中的所有其他内容

在我的应用模块中 gradle:

apply from: "../utils.gradle"

...

tasks.whenTaskAdded { task ->
    switch (task.name) {
        case 'bundleRelease':
            task.finalizedBy renameBundle
            break
    }
}

在utils.gradle中:

task renameBundle (type: Exec) {
    def baseName = getProperty('archivesBaseName')

    def stdout = new ByteArrayOutputStream()
    def stderr = new ByteArrayOutputStream()

    commandLine "copy.bat", rootProject.getProjectDir().getAbsolutePath() + "\release\${baseName}-release.aab", "<MY_AAB_PATH>\${baseName}.aab", "D:\Android\studio\release"
    workingDir = rootProject.getProjectDir().getAbsolutePath()
    ignoreExitValue true
    standardOutput stdout
    errorOutput stderr

    doLast {
        if (execResult.getExitValue() == 0) {
            println ":${project.name}:${name} > ${stdout.toString()}"
        } else {
            println ":${project.name}:${name} > ${stderr.toString()}"
        }
    }
}

copy.bat 在项目的文件夹中创建并包含:

COPY %1 %2
RMDIR /Q/S %3

注意第三个参数,确保您没有使用对您来说很重要的文件夹。

编辑:为什么您可能会问 2 个命令的 .BAT。如果您在 Windows 上尝试 commandLine "copy",... 它会导致 "system does not recognize the command copy"。输入任何内容,例如 COPY、REN、RENAME 等,都不起作用。

为什么没有人为此使用现有的 gradle 任务?

有一个类型为 FinalizeBundleTask 的 gradle 任务,它被称为包生成的最后一步,它正在做两件事:

  • 签署生成的 AAB 包
  • 移动并重命名请求的 AAB 包

您需要做的只是将此任务的“输出”更改为您想要的任何内容。此任务包含 属性 finalBundleFile - 最终 AAB 包的完整路径。

我正在使用它:

    applicationVariants.all {
        outputs.all {
            // AAB file name that You want. Falvor name also can be accessed here.
            val aabPackageName = "$App-v$versionName($versionCode).aab"
            // Get final bundle task name for this variant
            val bundleFinalizeTaskName = StringBuilder("sign").run {
                // Add each flavor dimension for this variant here
                productFlavors.forEach {
                    append(it.name.capitalizeAsciiOnly())
                }
                // Add build type of this variant
                append(buildType.name.capitalizeAsciiOnly())
                append("Bundle")
                toString()
            }
            tasks.named(bundleFinalizeTaskName, FinalizeBundleTask::class.java) {
                val file = finalBundleFile.asFile.get()
                val finalFile = File(file.parentFile, aabPackageName)
                finalBundleFile.set(finalFile)
            }
        }
    }

它与任何 flavorsdimensionsbuildTypes 完美配合。没有任何额外的任务,适用于 Toolbar -> Generate signed Bundle 中为输出设置的任何路径,可以为任何 flavor.

设置唯一名称