Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Gradle 如何在Kotlin中访问variant.outputFileName_Gradle_Kotlin_Android Gradle Plugin_Gradle Kotlin Dsl - Fatal编程技术网

Gradle 如何在Kotlin中访问variant.outputFileName

Gradle 如何在Kotlin中访问variant.outputFileName,gradle,kotlin,android-gradle-plugin,gradle-kotlin-dsl,Gradle,Kotlin,Android Gradle Plugin,Gradle Kotlin Dsl,我们一直在使用这样一个片段来重命名Gradle构建生成的APK文件: android.applicationVariants.all { variant -> variant.outputs.all { outputFileName = "${variant.name}-${variant.versionName}.apk" } } 资料来源: 我现在正在将我的build.gradle转换为build.gradle.kts,I。E到Gradle Kotli

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

android.applicationVariants.all { variant ->
    variant.outputs.all {
        outputFileName = "${variant.name}-${variant.versionName}.apk"
    }
}
资料来源:

我现在正在将我的
build.gradle
转换为
build.gradle.kts
,I。E到Gradle Kotlin DSL。这是最后缺少的部分之一:我不知道如何访问
outputFileName

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

  • BaseVariant.getOutputs()
    返回一个
    DomainObjectCollection
    ,该集合提供代码段中使用的
    all
    方法
  • BaseVariantOutput
    扩展了
    OutputFile
    ,该文件扩展了
    VariantOutput
    ,但它们都没有
    outputFileName
    或任何匹配名称的getter或setter

因此,我怀疑有一些先进的Groovy魔法在发挥作用——但我如何在Kotlin中实现这一点呢?

浏览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
            }
        })
    }
})
applicationVariants.all(对象:操作{
覆盖乐趣执行(变量:ApplicationVariant){
println(“变量:${variant}”)
变量.输出.全部(对象:操作{
覆盖乐趣执行(输出:BaseVariantOutput){
val outputImpl=输出为BaseVariantOutputImpl
val fileName=output.outputFileName
.replace(“-release”,“-release-v${defaultConfig.versionName}-vc${defaultConfig.versionCode}-$gitshash”)
.replace(“-debug”,“-debug-v${defaultConfig.versionName}-vc${defaultConfig.versionCode}-$gitshash”)
println(“输出文件名:${fileName}”)
outputImpl.outputFileName=文件名
}
})
}
})

所以,我想:是的,Groovy有一些魔力在发挥作用,即Groovy的动态类型系统允许您从代码中访问
getOutputFileName
setOutputFileName
(通过缩写的
outputImpl.outputFileName
语法,如Kotlin),希望它们在运行时出现,即使您知道的编译时接口没有它们。

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

android{
applicationVariants.all{
val variant=此
变量.输出
.map{it as BaseVariantOutputImpl}
.forEach{output->
output.outputFileName=output.outputFileName
.替换(“应用程序-”,“FooBar-”)
.replace(“.apk”和“-${variant.versionName}.${variant.versionCode}.apk”)
}
}
}

使用lambdas的较短版本:

    applicationVariants.all{
        outputs.all {
            if(name.contains("release"))
                (this as BaseVariantOutputImpl).outputFileName = "../../apk/$name-$versionName.apk"
        }
    }
这将把APK放入app/APK文件夹,其名称由变体名称和版本代码组成。
您可以根据需要更改文件名的格式。

重要提示:必须仅在发布版本上执行此操作,因为“.”in path会以奇怪的错误破坏调试生成过程。

向下投票者:需要解释吗?请解释一下此Syntax/示例,以及为什么我们仍然需要使用BaseVariantOutputImpl?因为我们需要强制转换它,所以我们可以访问setOutFileName@Zingamcmiiw@mochdawi那么这是因为Kotlin DSL中存在一些严重缺陷吗?根据我的经验,applicationVariants.forEach不起作用(集合为空),您必须使用applicationVariants.all{}。但不是Kotlin的扩展Iterable.all(),而是DomainObjectCollection.all()。非常感谢您提供了详细的解释+解决方案:)@david.miholaNote:您可以调用更简单的applicationVariants。所有{}(无需创建显式操作对象),并且您的ApplicationVariant将作为接收方参数传递。确保不要定义一些lambda参数:“.all{variant->”,否则它将匹配Kotlin的扩展函数。只需使用普通的“.all{”,您将得到更短更好的代码。