gradle--groovy-dsl和kotlin-dsl对比

gradle–groovy-dsl和kotlin-dsl对比

常用对比

  • groovy可以使用单引号和双引号,而kotlin只能使用双引号
  • groovy在函数调用时可以省略括号,而kotlin必须加上括号
  • groovy在赋值时可以省略等于号,而kotlin必须加上等号
  • 为了减少迁移成本,在groovy时就应该约定使用双引号,调用加上括号,使用等号赋值

插件引用对比

  • Groovy DSL有两种方式去引用插件:
    • 1 plugins{} //强烈推荐
    • 2 apply plugin
  • 注意,核心插件可以用短名称,非核心插件必须声明id和version(非核心插件地址:Gradle - Plugins)
//groovy dsl
plugins {
    id 'java' //核心插件,可以省略version
    id 'jacoco'
    id 'maven-publish'
    id 'org.springframework.boot' version '2.4.1'
}
//kotlin dsl
plugins {
    java //核心插件,可以直接用短名称
    jacoco
    `maven-publish`
    id("org.springframework.boot") version "2.4.1"
}
//groovy dsl
apply plugin: 'java'
apply plugin: 'jacoco'
apply plugin: 'org.springframework.boot'
//kotlin dsl
apply(plugin = "java")
apply(plugin = "jacoco")
apply(plugin = "org.springframework.boot")

//另外还有这种写法
apply<ExamplePlugin>()

gradle脚本引用对比

  • groovy
apply from: 'other.gradle'
  • kotlin
apply(from = "other.gradle.kts")

任务task对比

配置任务

// groovy-dsl
tasks.jar {
    archiveFileName = 'foo.jar'
}

tasks.named('jar') {
    archiveFileName = 'foo.jar'
}

tasks.getByName('jar') {
    archiveFileName = 'foo.jar'
}

tasks.named('test') {
  useJUnitPlatform()
}

// 指定编码
tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}

// 打包sourcesJar任务
task sourcesJar(type: Jar, dependsOn: classes) {
    archiveClassifier = 'sources'
    from sourceSets.main.allSource
}
// kotlin-dsl
tasks.jar {
    archiveFileName.set("foo.jar")
}

tasks.named<Jar>("jar") {
    archiveFileName.set("foo.jar")
}

tasks.getByName<Jar>("jar") {
    archiveFileName.set("foo.jar")
}

tasks.withType<Test> {
  useJUnitPlatform()
}

tasks.withType<JavaCompile> {
    options.encoding = "UTF-8"
}

// 打包sourcesJar任务
val sourcesJar by tasks.registering(Jar::class) {
    dependsOn("classes")
    archiveClassifier.set("sources")
    from(sourceSets["main"].allSource)
}

创建任务

// groovy-dsl
task greeting {
    doLast { println 'Hello, World!' }
}

tasks.create('greeting') {
    doLast { println('Hello, World!') }
}

tasks.register('greeting') {
    doLast { println('Hello, World!') }
}

tasks.register('docZip', Zip) {
    archiveFileName = 'doc.zip'
    from 'doc'
}

tasks.create(name: 'docZip', type: Zip) {
    archiveFileName = 'doc.zip'
    from 'doc'
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
// kotlin-dsl
task("greeting") {
    doLast { println("Hello, World!") }
}

tasks.create("greeting") {
    doLast { println("Hello, World!") }
}

tasks.register("greeting") {
    doLast { println("Hello, World!") }
}

tasks.register<Zip>("docZip") {
    archiveFileName.set("doc.zip")
    from("doc")
}

tasks.create<Zip>("docZip") {
    archiveFileName.set("doc.zip")
    from("doc")
}

tasks.register("clean", Delete::class) {
    delete(rootProject.buildDir)
}

仓库对比

// groovy-dsl
repositories {
        mavenLocal()
        google()
        mavenCentral()
        maven { url 'https://www.jitpack.io' }
    }
// kotlin-dsl
repositories {
        mavenLocal()
        google()
        mavenCentral()
        maven("https://www.jitpack.io")
    }

依赖对比

// groovy-dsl
plugins {
    id 'java-library'
}
dependencies {
    implementation 'com.example:lib:1.1'
    runtimeOnly 'com.example:runtime:1.0'
    testImplementation('com.example:test-support:1.3') {
        exclude(module: 'junit')
    }
    testRuntimeOnly 'com.example:test-junit-jupiter-runtime:1.3'
}
// kotlin-dsl
plugins {
    `java-library`
}
dependencies {
    implementation("com.example:lib:1.1")
    runtimeOnly("com.example:runtime:1.0")
    testImplementation("com.example:test-support:1.3") {
        exclude(module = "junit")
    }
    testRuntimeOnly("com.example:test-junit-jupiter-runtime:1.3")
}

groovy的ext和kotlin的extra

// groovy-dsl
// root build.gradle
...
ext {
	min_sdk = 21
    target_sdk = 31
}

//sub build.gradle
android {
    defaultConfig {
       	minSdk min_sdk //groovy的省略写法
        targetSdk rootProject.target_sdk
        }
}
// kotlin-dsl
// root build.gradle
...
rootProject.extra["min_sdk"] = 21
extra["target_sdk"] = 31

//sub build.gradle
val min_sdk: Int by rootProject.extra
android {
    defaultConfig {
        minSdk = rootProject.extra["min_sdk"] as Int 
        // minSdk = min_sdk //与上面等效
        targetSdk = rootProject.properties["target_sdk"] as Int
        }
}
  • 假如工程里groovy和kotln都有,那么kotlin可以通过 rootProject.extra[“min_sdk”]rootProject.properties[“target_sdk”] 得到groovy主工程中定义的ext,如下
// groovy-dsl
// root build.gradle
ext {
	min_sdk = 21
    target_sdk = 31
}

独立gradle文件对比

  • 在groovy中,当我们发现一个build.gradle文件比较庞大臃肿时,可以很方便地将其中部分内容独立成另一个xxx.gradle文件并用apply from进行引用
  • 然而当你使用kotlin-dsl时,你会发现上面的想法并不顺利,脚本根本无法正常执行,因为kotlin-dsl并不支持这样做,要实现类似的功能,还得使用预编译脚本插件Developing Custom Gradle Plugins

示例

  • 最后以android为例,提供一份对比

groovy

  • setting.gradle
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name = "My Application"
include ':app'

  • root build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.4"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

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

ext{
    min_sdk=21
    target_sdk =31
}
  • app build.gradle
plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdk 31

    defaultConfig {
        applicationId "com.xxx.myapplication"
        minSdk min_sdk
        targetSdk rootProject.target_sdk
        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'
    }
}

dependencies {
 	implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

kotlin

  • setting.gradle
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name = "My Application"
include(":app")

  • root build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:7.0.4")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20")

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle.groovy files
    }
}

tasks.register("clean", Delete::class) { 
    delete(rootProject.buildDir)
}

extra["min_sdk"] = 21
extra["target_sdk"] = 31
  • app build.gradle
plugins {
    id("com.android.application")
    id("kotlin-android")
}
android {
    compileSdk = 31

    defaultConfig {
        applicationId = "com.xxx.myapplication"
        minSdk = rootProject.properties["min_sdk"] as Int
        targetSdk = rootProject.properties["target_sdk"] as Int
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = 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"
    }
}

dependencies {
 	implementation (fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
    implementation("androidx.core:core-ktx:1.2.0")
    implementation("androidx.appcompat:appcompat:1.4.1")
    implementation("com.google.android.material:material:1.5.0")
    implementation("androidx.constraintlayout:constraintlayout:2.1.3")
    testImplementation("junit:junit:4.+")
    androidTestImplementation("androidx.test.ext:junit:1.1.3")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
}

参考