Android Studio 新版本 Gradle kotlin kts 多模块构建,改APK输出文件名,添加版本等信息, 路径

6,114 阅读3分钟

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