Android Studio 又升级了,Gradle 默认创建kts构建文件格式,调整幅度较大,做个笔记。
背景
- KTS比之前强了许多,基于kotlin语法,有了完善的代码提示。不再是瞎子摸象了。
- 我还是有点代码洁癖的,希望所有配置文件比较简洁,方便配置并且能够有比较好的代码提示。
- 较dsl的版本的配置改动较大,主要实现以下几个功能:
实现功能
- 输出文件改名,
- 多模块的配置共享
- 输出调整路径
- 发布时自动增加版本号
- 提取子模块公共依赖包, 统一更新版本,避免各个子模块依赖包版本不统一
- ...
配置文件
主要是两个文件,模块文件和项目配置,详细注释在代码里
- 有些功能虽然可以用buildSrc实现,但较为繁琐,不方便在项目之间复制。另外也会导致编译速度变慢,因此不使用此方法。
- TODO: 未解决的问题,想将项目公共配置抽离出来,作为一个单独的配置文件,如xxx.gradle.kts,但没有成功,编译时无法找到这个脚本,找到办法后可以再完善一下。
根目录下的项目配置文件:build.gradle.kts
// 导入定义
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
// 定义公共的子模块使用的SDK版本号
val sdkVersion=33
val outputApkDir = File("e:\releasedApk")
// 定义引用插件
plugins {
id("com.android.application") version "8.1.0" apply false
id("org.jetbrains.kotlin.android") version "1.8.0" apply false
id("com.android.library") version "8.1.0" apply false
}
/**
* 读取子模块的版本名称。
*/
fun projectVersionName(project:Project):String{
val versionFile = project.file("version.properties")
var ver = "1.0.0"
if(versionFile.canRead()){
val prop = java.util.Properties()
versionFile.inputStream().use {
prop.load(it)
if(prop["VERSION"] != null){
ver = prop["VERSION"] as String
}
}
}
return ver
}
/**
* 读取子模块的版本数字
*/
fun projectVersionCode(project:Project):Int{
val ver = projectVersionName(project);
val sp = ver.split(".")
val v1 = Integer.parseInt(sp[0])
val v2 = Integer.parseInt(sp[1])
val v3 = Integer.parseInt(sp[2])
return v1 * 100000 + v2 * 1000 + v3
}
// 增加子模块的版本号
fun projectIncVersion(project:Project):String{
val ver = projectVersionName(project);
val sp = ver.split(".")
val v1 = Integer.parseInt(sp[0])
val v2 = Integer.parseInt(sp[1])
val v3 = Integer.parseInt(sp[2])+1
val newVer = String.format("%d.%d.%d", v1, v2, v3)
val prop = java.util.Properties()
val versionFile = project.file("version.properties")
versionFile.writer().use {
prop["VERSION"] = newVer
prop.store(it,null)
}
return newVer
}
// 建议所有项目共用的配置。
allprojects{
// 子模块的配置,即子模块配置中的android{}部分,指定类型可以使自动提示能够工作。
// 这里的定义,将会自动混入子项目
val appConfig:BaseAppModuleExtension.()->Unit = {
// 设置SDK版本
compileSdk = sdkVersion
// 定义缺省配置。
defaultConfig{
// 设置子项目的版本号。
versionCode = projectVersionCode(project)
versionName = projectVersionName(project)
// 设置SDK版本
targetSdk = sdkVersion
}
// 定义签名配置
signingConfigs {
// 创建签名配置
create("signing"){
storeFile=file(projectDir.parent + "/xxx.jks")
storePassword="xxx"
keyAlias = "xxx"
keyPassword = "xxx"
}
}
// 打包改名
applicationVariants.all {
outputs.all {
val ver = defaultConfig.versionName
val minSdk = project.extensions.getByType(BaseAppModuleExtension::class.java).defaultConfig.minSdk
val abi = filters.find{it.filterType == "ABI"}?.identifier ?:"all"
(this as com.android.build.gradle.internal.api.BaseVariantOutputImpl).outputFileName =
"${project.name}-$ver-${abi}-sdk$minSdk.apk";
}
}
// 定义公共依赖
dependencies {
add("implementation", "org.jetbrains.kotlin:kotlin-stdlib:1.8.22")
add("implementation", "androidx.core:core-ktx:1.9.0")
add("implementation", "androidx.appcompat:appcompat:1.6.1")
add("implementation", "com.google.android.material:material:1.8.0")
add("implementation", "androidx.constraintlayout:constraintlayout:2.1.4")
add("implementation", "com.google.code.gson:gson:2.10.1")
// 添加本地子模块依赖
add("implementation", project(mapOf("path" to ":common")))
}
}
// 应用配置,保存配置到 "extra" 中,以便在子模块中使用。
extra["appConfig"]= appConfig
// 定义增加版本的任务。
task("incVersion"){
group = "android"
doFirst {
projectIncVersion(project)
}
}
// 定义发布任务
task("releaseApk") {
dependsOn("assembleRelease","incVersion")
group = "android"
doLast {
// 查找build Apk的文件
val releaseDir = File(project.buildDir.absolutePath , "/outputs/apk/release/")
val apkFiles = releaseDir.listFiles()?.filter {
it.extension == "apk"
}
// 移动所有的apk到公共的发布目录。
val outputDir = File(outputApkDir, project.name)
if(outputDir.exists()){
outputDir.deleteRecursively()
}
outputDir.mkdirs()
apkFiles?.forEach {
val toFile = File(outputDir, it.name)
it.renameTo(toFile)
println(toFile.absolutePath)
}
println("=== released apk:${project.name} ===")
}
}
}
子模块目录下的项目配置文件:build.gradle.kts
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
android {
// 引入在根目录定义的公共的配置
@Suppress("UNCHECKED_CAST")
apply (extra["appConfig"] as BaseAppModuleExtension.()->Unit)
// compileSdk = 33 // 删除此项,使用公共的配置
namespace = "cn.magicmind.msc.apk6.plugins.geckoview"
defaultConfig {
applicationId = "cn.magicmind.msc.apk6.plugins.geckoview"
minSdk = 19
// targetSdk = 33 // 删除此项,使用公共的配置
multiDexEnabled = true
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
viewBinding {
enable=true
}
// BUILD 类型配置
buildTypes {
release {
isMinifyEnabled= false
proguardFiles (getDefaultProguardFile("proguard-android-optimize.txt"), "$projectDir/proguard-rules.pro")
// 使用公共的签名配置
signingConfig = signingConfigs.getByName("signing")
}
debug {
isMinifyEnabled= false
// 使用公共的签名配置
signingConfig = signingConfigs.getByName("signing")
}
}
// 定义分包
splits {
abi {
this.isEnable = true
this.isUniversalApk = false
reset()
this.include("armeabi-v7a", "arm64-v8a" ) // "x86", "x86_64"
}
}
}
dependencies {
implementation("org.mozilla.geckoview:geckoview:109.0.20230109161414")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}