gradle脚本改造from Groovy to Kotlin

文章目录

    • 前言
      • 什么是Kotlin DSL
      • 关于Gradle脚本改造
        • settings.gradle改造
        • 工程目录下build.gradle改造
        • app下build.gradle改造
      • 问题记录
        • Unresolved reference
        • 关于ndk模块修改
        • 设置不起作用
      • 加餐
        • 补充1:gradle3.0前后依赖配置项改变对比表
        • 补充2:gradle的几个实用小技巧

前言

前文buildSrc使用,依赖统一管理。gradle版本一升级我就懵逼,经常在gradle和kts之间来回切,记录一下。

什么是Kotlin DSL

DSL全程使Domain Specific Language,领域特定语言。kotlin中常用实现使使用高阶函数以及infix,这里不多提。kts脚本里面使用到了很多dsl,所以能实现之前gradle脚本相似的功能。

Android Studio是使用Gradle来编译,而默认的构建语言是Groovy,但是Gradle实际上是支持Kotlin来编写Gradle构建脚本的,常见的构建脚本是.gradle结尾,而Koltin语法编写的脚本则是.gradle.kts。

Gradle官网也是给出了Groovy迁移Kotlin的指导文章:Migrating build logic from Groovy to Kotlin

关于Gradle脚本改造

首先后缀从.gradle修改为 gradle.kts,有几个注意点

  1. Groovy字符串可以用单引号’string’或双引号引起来"string",而Kotlin需要双引号"string"。
  2. Groovy允许在调用函数时省略括号,而Kotlin始终需要括号
  3. adle Groovy DSL允许=在分配属性时省略赋值运算符,而Kotlin始终需要赋值运算符
  4. 部分设置字段变动了,部分以前能直接写的需要通过getByName获取了。
//示例
 buildTypes {
 	//release变成了getByName("release") 
	getByName("release") {
		//minifyEnabled变成了isMinifyEnabled
	 	isMinifyEnabled = false
	}
}
  • settings.gradle改造

改造前

rootProject.name = "MyApplication"
include ':app' 
include ':common'

改造后

rootProject.name = "MyApplication"
include(":app")
include(":common")
  • 工程目录下build.gradle改造

改造前

buildscript {
    repositories {
       	google()
        mavenCentral()
        maven { url "https://jitpack.io" }
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.1.2"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.31"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url "https://jitpack.io" }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

改造后

buildscript {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
//        maven { url=uri("https://maven.aliyun.com/repository/public") }
//        maven { url=uri("https://maven.aliyun.com/repository/google/") }
//        maven { url=uri("https://maven.aliyun.com/repository/gradle-plugin")}
    }
    dependencies {
        classpath("com.android.tools.build:gradle:4.1.2")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.31")
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
//        maven { url = uri("https://maven.aliyun.com/repository/public") }
//        maven { url=uri("https://maven.aliyun.com/repository/google/") }
//        maven { url=uri("https://maven.aliyun.com/repository/gradle-plugin")}
    }
}

tasks.register("clean", Delete::class) {
    delete(rootProject.buildDir)
}
  • app下build.gradle改造

改造前

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-parcelize'
    id 'kotlin-kapt'
}

android {
    compileSdk 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.phz.myapplication"
        minSdk 21
        targetSdk 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    buildFeatures {
        viewBinding true
    }
}

dependencies {
	implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

修改后

plugins {
    id("com.android.application")
    kotlin("android")//id("kotlin-android")
    kotlin("kapt")
    id("kotlin-parcelize")
}

android {
    compileSdk = BuildConfig.compileSdkVersion

    defaultConfig {
        applicationId = BuildConfig.applicationId
        minSdk = BuildConfig.minSdkVersion
        targetSdk = BuildConfig.targetSdkVersion
        versionCode = BuildConfig.versionCode
        versionName = BuildConfig.versionName
        testInstrumentationRunner = BuildConfig.testInstrumentationRunner

        multiDexEnabled = true
    }

    base{
        //Android Studio 默认通过构建类型名称添加 versionNameSuffix
        //输出包名示例:BlueToothHelper(1.0.0)-release
        archivesBaseName = "BlueToothHelper(${BuildConfig.versionName})"
    }

    buildTypes {
        getByName("release") {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
            versionNameSuffix ="-R"
        }
        lintOptions {
            isCheckReleaseBuilds = false
            isAbortOnError = false
        }
    }
    packagingOptions {
        resources.excludes += "META-INF/gradle/incremental.annotation.processors"
    }
    compileOptions {
//        sourceCompatibility = JavaVersion.VERSION_11
//        targetCompatibility = JavaVersion.VERSION_11
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
//        jvmTarget = 11
        jvmTarget = "1.8"
    }
    buildFeatures {
        dataBinding = true
        viewBinding = true
    }
}

dependencies {
    implementation(fileTree(mapOf("include" to listOf("*.jar"), "dir" to "libs")))
    implementation(project(mapOf("path" to ":common")))
    implementation(AndroidX.coreKtx)
    implementation(AndroidX.appcompat)
    
    testImplementation(Testing.junit)
    androidTestImplementation(Testing.androidJunit)
    androidTestImplementation(Testing.espresso)

    //material包
    implementation(Google.material)
}

问题记录

Unresolved reference

gradle Unresolved reference:outputFileName

其实这个问题挺常见的,首先随着gradle版本的升级,某些命令不支持了。然后是因为gradle变成了kts?(内心os:还是gradle懂得太少)

关于ndk模块修改

import kotlin.collections.*

android {
    compileSdk = BuildConfig.compileSdkVersion

    defaultConfig {
        ndk {
            abiFilters.addAll(arrayListOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64"))
        }
	}
}

设置不起作用

以前写的设置不起作用了,以一个修改打包名字的设置为例:

 applicationVariants.all { variant ->
      variant.outputs.all { output ->
          def fileName = "yxx_${variant.versionName}.apk"
          def outFile = output.outputFile
          if (outFile != null && outFile.name.endsWith('.apk')) {
              outputFileName = fileName
          }
      }
}

尝试转换成kotlin后:

applicationVariants.all { variant ->
    variant.outputs.all { output ->
        val fileName = "yxx_${variant.versionName}.apk"
        val outFile = output.outputFile
        if (outFile != null && outFile.name.endsWith(".apk")) {
            val file=File(outFile.parent, fileName)
            if (file.exists()){
                file.delete()
            }
            outFile.renameTo(file)
        }
        true
    }
    true
}

尝试打包发现包名没有变化,不知道哪里出了问题,只好这样写了:

    base{
        archivesBaseName = "yxx(${BuildConfig.versionName})"
    }

加餐

补充1:gradle3.0前后依赖配置项改变对比表

3.0之前 3.0之后 备忘
compile implementation 其他模块只有在运行时才能使用该依赖项。(不具有传递性)
compile api 该方式依赖的库将会参与编译和打包。(依赖具有传递性)
provided compileOnly 编译时有效,不参与打包。(常用于依赖一些容易冲突的包)
apk runtimeOnly Gradle 只会将依赖项添加到构建输出,以便在运行时使用。
compile annotationProcessor 将编译类路径与注释处理器类路径分开

补充2:gradle的几个实用小技巧

  1. gradle build --scan命令用于查看依赖树
    详见gradle常见的问题记录,同一个库导了几个版本的包,如何查看依赖树并手动排除。
  2. gradle模块化
    如果用过greendao之类的库,应该有所了解。
apply plugin: 'org.greenrobot.greendao'

greendao {
    schemaVersion 1 //数据库版本号
    //省略...
}

//省略...

其实我们可以新建一个greendao-config.gradle文件,把这块放进去。然后导入gradle。这样做的好处就是精简了gradle代码,而且遵循单一职责原则。

apply from '../greendao-config.gradle'
  1. 资源文件分包
    string.xml太大不好找?colors.xml颜色太多?没关系,我们可以按照模块对res进行分包。
android {
    sourceSets {
        main {
            res.srcDirs(
                    'src/main/res',
                    'src/main/res_core',
                    'src/main/res_seed',
            )
        }
    }
}

然后就可以在res_core包下放资源了,值得注意的是,虽然是分包,但是资源还是可以相互拿的,只要不冲突。
4. buildSrc+kotlin可以提供全局复用的依赖管理。
5. 遍历方式依赖写法。
config.gradle

ext{
    dependencies = [
            // base
            "appcompat": "androidx.appcompat:appcompat:1.3.0",
            //省略其他...
    ]
}
//省略其他...

在build.gradle里引用

apply from config.gradle

def implementationDependencies = project.ext.dependencies
//省略其他...
dependencies{
implementationDependencies.each { k, v -> implementation v }   
//当然除了implementation 还有其他的,比如kapt/annotationProcessor
}

你可能感兴趣的:(Kotlin,Android)