如何在 Kotlin 中访问variant.outputFileName

问题描述 投票:0回答:5

我们一直在使用像这样的代码片段来重命名由 Gradle 构建生成的 APK 文件:

android.applicationVariants.all { variant ->
    variant.outputs.all {
        outputFileName = "${variant.name}-${variant.versionName}.apk"
    }
}

来源:https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration#variant_output

我现在正在将我的

build.gradle
转换为
build.gradle.kts
,i。 e.到 Gradle Kotlin DSL。这是最后缺失的部分之一:我不知道如何访问
outputFileName

根据 API 文档,它甚至似乎不存在:

  • BaseVariant.getOutputs()
    返回一个
    DomainObjectCollection<BaseVariantOutput>
    ,它提供了代码片段中使用的
    all
    方法。
  • BaseVariantOutput
    扩展了
    OutputFile
    扩展了
    VariantOutput
    但这些都没有
    outputFileName
    或任何匹配名称的 getter 或 setter。

所以,我怀疑有一些高级的 Groovy 魔法在起作用,可以让这项工作成功 - 但我如何在 Kotlin 中实现这一目标?

gradle kotlin android-gradle-plugin gradle-kotlin-dsl
5个回答
54
投票

@david.mihola 答案的一个简化版本:

android {

    /**
    * Notes Impl: Use DomainObjectCollection#all
    */
    applicationVariants.all {
        val variant = this
        variant.outputs
            .map { it as com.android.build.gradle.internal.api.BaseVariantOutputImpl }
            .forEach { output ->
                val outputFileName = "YourAppName - ${variant.baseName} - ${variant.versionName} ${variant.versionCode}.apk"
                println("OutputFileName: $outputFileName")
                output.outputFileName = outputFileName
            }
    }

}

32
投票

浏览Android Gradle插件的源代码,我想我找到了答案 - 开始吧:

我们实际上正在处理类型为

BaseVariantOutputImpl
的对象,并且该类 具有这两种方法:

public String getOutputFileName() {
    return apkData.getOutputFileName();
}

public void setOutputFileName(String outputFileName) {
    if (new File(outputFileName).isAbsolute()) {
        throw new GradleException("Absolute path are not supported when setting " +
                    "an output file name");
    }
    apkData.setOutputFileName(outputFileName);
}

利用这些知识我们现在可以:

import com.android.build.gradle.internal.api.BaseVariantOutputImpl

然后像这样投射我们的目标对象:

applicationVariants.all(object : Action<ApplicationVariant> {
    override fun execute(variant: ApplicationVariant) {
        println("variant: ${variant}")
        variant.outputs.all(object : Action<BaseVariantOutput> {
            override fun execute(output: BaseVariantOutput) {

                val outputImpl = output as BaseVariantOutputImpl
                val fileName = output.outputFileName
                        .replace("-release", "-release-v${defaultConfig.versionName}-vc${defaultConfig.versionCode}-$gitHash")
                        .replace("-debug", "-debug-v${defaultConfig.versionName}-vc${defaultConfig.versionCode}-$gitHash")
                println("output file name: ${fileName}")
                outputImpl.outputFileName = fileName
            }
        })
    }
})

所以,我猜:是的,有一些 Groovy 魔法在起作用,即 Groovy 的动态类型系统允许您仅访问

getOutputFileName
setOutputFileName
(通过缩写的
outputImpl.outputFileName
语法,如 Kotlin 中)您的代码,希望它们在运行时存在,即使您知道的编译时接口没有它们。


13
投票

使用 lambda 的较短版本:

    applicationVariants.all{
        outputs.all {
            if(name.contains("release"))
                (this as BaseVariantOutputImpl).outputFileName = "../../apk/$name-$versionName.apk"
        }
    }

这会将 APK 放入 app/apk 文件夹中,名称由变体名称和版本代码组成。
您可以根据需要更改文件名的格式。
重要提示:它只能在发布版本上完成,因为路径中的“..”会破坏调试构建过程并产生奇怪的错误。


4
投票

对于

libraryVariants
可以在不访问内部 api 的情况下更改输出文件名:

    libraryVariants.all {
        outputs.all {
            packageLibraryProvider {
                archiveFileName.set("yourlibrary-${buildType.name}.aar")
            }
        }
    }

3
投票

更新 04/12/23:请谨慎操作,@Mike 评论说这样的配置可能会影响您的项目,据我所知,我对此没有任何问题,仍然使用之前共享的配置重命名我的 APK。

原答案:

对于 Kotlin KTS。

注意:这被认为是一个临时解决方案,直到 Android 团队发布在 KTS 中执行此操作的正确方法为止。

在 AGP v7.1.2 中工作,它也可能在较低版本的 AGP 中工作。

:应用程序构建.gradle

android {

// ...

    this.buildOutputs.all {

        val variantOutputImpl = this as com.android.build.gradle.internal.api.BaseVariantOutputImpl

        val variantName: String = variantOutputImpl.name

        val outputFileName = "custom-name-${variantName}.apk"
        
        variantOutputImpl.outputFileName = outputFileName
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.