How to access variant.outputFileName in Kotlin

后端 未结 3 1844
抹茶落季
抹茶落季 2021-01-01 19:28

We\'ve been using a snippet like this one to rename the APK file generated by our Gradle build:

android.applicationVariants.all { variant ->
    variant.o         


        
相关标签:
3条回答
  • 2021-01-01 20:08

    Browsing through the source code of the Android Gradle plugin, I think I found the answer - here we go:

    We are actually dealing with objects of type BaseVariantOutputImpl and this class does have both these methods:

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

    Using this knowledge we can now:

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

    and then cast our target objects like so:

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

    So, I guess: Yes, there is some Groovy magic at work, namely that Groovy's dynamic type system allows you to just access getOutputFileName and setOutputFileName (by way of the abbreviated outputImpl.outputFileName syntax, as in Kotlin) from your code, hoping they will be there at runtime, even if the compile time interfaces that you know about don't have them.

    0 讨论(0)
  • 2021-01-01 20:11

    A little simplified version of @david.mihola answer:

    android {
    
        applicationVariants.all {
            val variant = this
            variant.outputs
                    .map { it as BaseVariantOutputImpl }
                    .forEach { output ->
                        output.outputFileName = output.outputFileName
                                .replace("app-", "FooBar-")
                                .replace(".apk", "-${variant.versionName}.${variant.versionCode}.apk")
                    }
        }
    
    }
    
    0 讨论(0)
  • 2021-01-01 20:32

    Shorter version using lambdas:

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

    This will place APK into app/apk folder with name made of variant name and version code.
    You can change the format of filename as you wish.
    Important: it must be done only on release builds, because ".." in path corrupts debug build process with strange errors.

    0 讨论(0)
提交回复
热议问题