我们一直在使用像这样的代码片段来重命名由 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 中实现这一目标?
@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
}
}
}
浏览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 中)您的代码,希望它们在运行时存在,即使您知道的编译时接口没有它们。
使用 lambda 的较短版本:
applicationVariants.all{
outputs.all {
if(name.contains("release"))
(this as BaseVariantOutputImpl).outputFileName = "../../apk/$name-$versionName.apk"
}
}
这会将 APK 放入 app/apk 文件夹中,名称由变体名称和版本代码组成。
您可以根据需要更改文件名的格式。
重要提示:它只能在发布版本上完成,因为路径中的“..”会破坏调试构建过程并产生奇怪的错误。
对于
libraryVariants
可以在不访问内部 api 的情况下更改输出文件名:
libraryVariants.all {
outputs.all {
packageLibraryProvider {
archiveFileName.set("yourlibrary-${buildType.name}.aar")
}
}
}
更新 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
}
}