最近新学习了一下Kotlin,然后做一个Springboot的项目基础脚手架,在创建新项目的时候发现gradle脚本也支持Kotlin了,索性做一个纯粹的,全用Kotlin,我觉得现在入Kotlin已经挺晚的了,没想到还有坑😂
下面先说结论,正忙的老铁一把Ctrl+C就走,记得再回来好评啊
ext { set("logbackVersion", "1.1.1")
实际上在allprojects中的ext和groovy语言版本的使用方法相同,只是语言不同,需要转换一下
子模块的build.gradle.kts中的ext{}
dependencies { //注意ext在dependencies里面 ext { set("logbackVersion", "1.1.1") testImplementation("junit:junit:4.12") implementation("org.slf4j:slf4j-api:1.7.7") // 读取方法${ext.get("logbackVersion"),不熟悉的请复习Kotlin implementation("ch.qos.logback:logback-core:${ext.get("logbackVersion")}") implementation("ch.qos.logback:logback-classic:${ext.get("logbackVersion")}")
★20210824更新,子模块可以使用allprojects中定义的ext,方法如下:
dependencies testImplementation("junit:junit:4.12") implementation("org.slf4j:slf4j-api:1.7.7") // 不同的是加了一个project implementation("ch.qos.logback:logback-core:${project.ext.get("logbackVersion")}") implementation("ch.qos.logback:logback-classic:${project.ext.get("logbackVersion")}")
原因在于子模块中也有自己的ext对象,ext对象覆盖了allprojects中的变量的作用域,使用子模块的内置对象project就可以获取到project的全局定义
👉父模块allprojects中的ext{}或项目的中的ext{}
关于父模块或项目的的ext{}实际上没有太多可讲的,只是从groovy语言格式换成kotlin即可
- ext中调用set方法添加需要配置的参数,
有心的同学如果是idea开发,可以Ctrl点set跟过去看看,会发现这个是
ExtraPropertiesExtension
接口的一个方法void set(String name, @Nullable Object value);
- 在使用中注意是ext.get(“XXX”),注意括号里使用双引号
groovy版本:buildscript { ext { dependencyManagementPluginVersion = '1.0.4.RELEASE' springBootVersion = '2.0.3.RELEASE' dependencies { classpath("io.spring.gradle:dependency-management-plugin:${dependencyManagementPluginVersion}") classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
Kotlin版本:
buildscript { ext { set("dependencyManagementPluginVersion", "1.0.4.RELEASE") set("springBootVersion", "2.0.3.RELEASE") dependencies { classpath("io.spring.gradle:dependency-management-plugin:${ext.get("dependencyManagementPluginVersion")}") classpath("org.springframework.boot:spring-boot-gradle-plugin:${ext.get("springBootVersion")}")
具体所有Groovy转Kotlin的规则,请见gradle官方指南:
Migrating build logic from Groovy to Kotlin👉子模块的build.gradle.kts中的ext{}
子模块的ext才真是这篇要讲的重点问题
原springboot脚手架的子模块build.gradle的groovy脚本如下(示例):group = "com.muchenxinxi" version = "1.0.0" ext { springfoxVersion = "2.9.2" mapstructVersion = "1.3.0.Final" lombokVersion = "1.18.12" dependencies { // Swagger 自动生成接口文档 compile "io.springfox:springfox-swagger2:${springfoxVersion}" compile "io.springfox:springfox-swagger-ui:${springfoxVersion}"
转换成build.gradle.kts如下(示例):
ext { set("springfoxVersion", "2.9.2") set("mapstructVersion", "1.3.0.Final") dependencies { // Swagger 自动生成接口文档 implementation("io.springfox:springfox-swagger2:${ext.get("springfoxVersion")}") implementation("io.springfox:springfox-swagger-ui:${ext.get("springfoxVersion")}")
眼看IDEA没有飘红,心想是成了,于是果断点了刷新按钮,应用gradle的变更,结果buid窗口蹦了出来(构建错误):
org.gradle.internal.exceptions.LocationAwareException: Build file 'D:\MyPlayground\KotlinSpringboot\app-service\build.gradle.kts' line: 20 Cannot get property 'springfoxVersion' on extra properties extension as it does not exist at Program.execute(Unknown Source) at Program.execute(Unknown Source) at java.lang.Thread.run(Thread.java:748) Caused by: org.gradle.api.plugins.ExtraPropertiesExtension$UnknownPropertyException: Cannot get property 'springfoxVersion' on extra properties extension as it does not exist at Build_gradle$2.invoke(build.gradle.kts:20) at Build_gradle$2.invoke(build.gradle.kts:1) at Build_gradle.<init>(Unknown Source)
看意思是说没有找到
springfoxVersion
这个值在extension(ext)中不存在,What?(问号脸)
明明在dependencies上面写了呀,我TM在Groovy都没毛病。。。这。。。
经过从网上一番搜索,有给出以下方案:
1.使用val定义常量,然后在dependencies直接${valName}使用
2.在allprojects中定义
实测,以上两种方式确实可以解决问题,但是想想:val定义常量?总觉得有点别扭;在allprojects中定义?那怎么能行,子模块的内容写到父项目的配置,显然不合理正苦思冥想,突然发现父项目的build.gradle.kts的allproejct后面有个小标签
this: Project
像这样:
allprojects {this: Project
}
这不就是这个对象就是一个变量传给了某个方法的那种提示吗?
Ctrl跟过去是这样的:
ProjectDelegate.kt文件中:override fun allprojects(action: Action<in Project>) = delegate.allprojects(action)
对应的是这个函数
* Configures the dependencies for this project. * Executes the given configuration block against the [DependencyHandlerScope] for this * project. * @param configuration the configuration block. fun Project.dependencies(configuration: DependencyHandlerScope.() -> Unit) = DependencyHandlerScope.of(dependencies).configuration()
接着再ctrl从dependencies
跟了过去:
dependencies{this: DenpendencyHandlerScop
}
发现跳转到了ProjectExtension.kt文件指向了这个函数,从子模块的
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. package org.gradle.kotlin.dsl import org.gradle.api.Action import org.gradle.api.Incubating import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.ExternalModuleDependency import org. gradle.api.artifacts.ModuleDependency import org.gradle.api.artifacts.dsl.DependencyConstraintHandler import org.gradle.api.artifacts.dsl.DependencyHandler import org.gradle.kotlin.dsl.support.delegates.DependencyHandlerDelegate * Receiver for `dependencies` block providing convenient utilities for configuring dependencies. * @see [DependencyHandler] open class DependencyHandlerScope private constructor( val dependencies: DependencyHandler ) : DependencyHandlerDelegate() { companion object { fun of(dependencies: DependencyHandler): DependencyHandlerScope = DependencyHandlerScope(dependencies) override val delegate: DependencyHandler get() = dependencies @Deprecated(replaceWith = ReplaceWith("constraints"), message = "This method shouldn't be called because the most specific variant should be preferred by the Kotlin compiler", level = DeprecationLevel.HIDDEN) override fun constraints(configureAction: Action<in DependencyConstraintHandler>) { super.constraints(configureAction) * Configures dependency constraint for this project. * @param configureAction the action to use to configure module metadata * @since 6.3 @Incubating fun constraints(configureAction: DependencyConstraintHandlerScope.() -> Unit) { super.constraints { t -> configureAction(DependencyConstraintHandlerScope.of(t)) } * Adds a dependency to the given configuration. * @param dependencyNotation notation for the dependency to be added. * @return The dependency. * @see [DependencyHandler.add] operator fun String.invoke(dependencyNotation: Any): Dependency? = dependencies.add(this, dependencyNotation) * Adds a dependency to the given configuration. * @param dependencyNotation notation for the dependency to be added. * @param dependencyConfiguration expression to use to configure the dependency. * @return The dependency. * @see [DependencyHandler.add] inline operator fun String.invoke(dependencyNotation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit): ExternalModuleDependency = dependencies.add(this, dependencyNotation, dependencyConfiguration) * Adds a dependency to the given configuration. * @param group the group of the module to be added as a dependency. * @param name the name of the module to be added as a dependency. * @param version the optional version of the module to be added as a dependency. * @param configuration the optional configuration of the module to be added as a dependency. * @param classifier the optional classifier of the module artifact to be added as a dependency. * @param ext the optional extension of the module artifact to be added as a dependency. * @return The dependency. * @see [DependencyHandler.add] operator fun String.invoke( group: String, name: String, version: String? = null, configuration: String? = null, classifier: String? = null, ext: String? = null ): ExternalModuleDependency = dependencies.create(group, name, version, configuration, classifier, ext).apply { add(this@invoke, this) } * Adds a dependency to the given configuration. * @param group the group of the module to be added as a dependency. * @param name the name of the module to be added as a dependency. * @param version the optional version of the module to be added as a dependency. * @param configuration the optional configuration of the module to be added as a dependency. * @param classifier the optional classifier of the module artifact to be added as a dependency. * @param ext the optional extension of the module artifact to be added as a dependency. * @param dependencyConfiguration expression to use to configure the dependency. * @return The dependency. * @see [DependencyHandler.create] * @see [DependencyHandler.add] inline operator fun String.invoke( group: String, name: String, version: String? = null, configuration: String? = null, classifier: String? = null, ext: String? = null, dependencyConfiguration: ExternalModuleDependency.() -> Unit ): ExternalModuleDependency = dependencies.add(this, create(group, name, version, configuration, classifier, ext), dependencyConfiguration) * Adds a dependency to the given configuration. * @param dependency dependency to be added. * @param dependencyConfiguration expression to use to configure the dependency. * @return The dependency. * @see [DependencyHandler.add] inline operator fun <T : ModuleDependency> String.invoke(dependency: T, dependencyConfiguration: T.() -> Unit): T = dependencies.add(this, dependency, dependencyConfiguration) * Adds a dependency to the given configuration. * @param dependencyNotation notation for the dependency to be added. * @return The dependency. * @see [DependencyHandler.add] operator fun Configuration.invoke(dependencyNotation: Any): Dependency? = add(name, dependencyNotation) * Adds a dependency to the given configuration. * @param dependencyNotation notation for the dependency to be added. * @param dependencyConfiguration expression to use to configure the dependency. * @return The dependency. * @see [DependencyHandler.add] inline operator fun Configuration.invoke(dependencyNotation: String, dependencyConfiguration: ExternalModuleDependency.() -> Unit): ExternalModuleDependency = add(name, dependencyNotation, dependencyConfiguration) * Adds a dependency to the given configuration. * @param group the group of the module to be added as a dependency. * @param name the name of the module to be added as a dependency. * @param version the optional version of the module to be added as a dependency. * @param configuration the optional configuration of the module to be added as a dependency. * @param classifier the optional classifier of the module artifact to be added as a dependency. * @param ext the optional extension of the module artifact to be added as a dependency. * @return The dependency. * @see [DependencyHandler.add] operator fun Configuration.invoke( group: String, name: String, version: String? = null, configuration: String? = null, classifier: String? = null, ext: String? = null ): ExternalModuleDependency = create(group, name, version, configuration, classifier, ext).apply { add(this@invoke.name, this) } * Adds a dependency to the given configuration. * @param group the group of the module to be added as a dependency. * @param name the name of the module to be added as a dependency. * @param version the optional version of the module to be added as a dependency. * @param configuration the optional configuration of the module to be added as a dependency. * @param classifier the optional classifier of the module artifact to be added as a dependency. * @param ext the optional extension of the module artifact to be added as a dependency. * @param dependencyConfiguration expression to use to configure the dependency. * @return The dependency. * @see [DependencyHandler.create] * @see [DependencyHandler.add] inline operator fun Configuration.invoke( group: String, name: String, version: String? = null, configuration: String? = null, classifier: String? = null, ext: String? = null, dependencyConfiguration: ExternalModuleDependency.() -> Unit ): ExternalModuleDependency = add(this.name, create(group, name, version, configuration, classifier, ext), dependencyConfiguration) * Adds a dependency to the given configuration. * @param dependency dependency to be added. * @param dependencyConfiguration expression to use to configure the dependency. * @return The dependency. * @see [DependencyHandler.add] inline operator fun <T : ModuleDependency> Configuration.invoke(dependency: T, dependencyConfiguration: T.() -> Unit): T = add(name, dependency, dependencyConfiguration) * Configures the dependencies. inline operator fun invoke(configuration: DependencyHandlerScope.() -> Unit) = this.configuration()dependencies
跟过去也是这里
显然DependencyHandlerScope.of()处理父项目和子项目的配置
继续Ctrl跟到DependencyHandlerScope类What?!我看到了ext?再结合
我们在新建一个项目然后直接进行Build apk,可以生成一个app_debug.apk的apk文件,那么文件是怎么产生的呢?版本号在gradle文件夹下 libs.versions.toml文件中添加。(1)[versions]部分用于声明可以被依赖项引用的版本。(2)[libraries]部分用于声明坐标的别名。(3)[bundles]部分用于声明依赖包。(4)[plugins]部分用于声明插件。 网上有些视频教程讲解过程中,在讲解如何将Java和kotlin一起使用的时,在编辑build.gradle时,步骤如下: ① 修改build.gradle -> build.gradle.kts ② 在build.gradle.kts中添加 plugins { application; kotlin("jvm"); application { mainClassName = "Main"; dependencies { compile(kotlin("s... 虽然与 Groovy 相比,KTS 当前能更好地在 Android Studio 的代码编辑器中集成,但采用 KTS 的构建速度往往比采用 Groovy 慢,因此在迁移到 KTS 时应考虑构建性能。在kts中写法为:implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))。一个好的策略是首先对所有不明确的语句进行属性分配,然后通过将失败的语句转换为函数调用来修复构建。代码块指定的自定义存储库中提供的插件。 啥是插件?为啥要自定义插件? 其实插件就是一系列特定任务的Task,这些Task具有特殊的功能,比如安卓工程的默认gradle插件就有好多Task:build、clean等。目前使用AS编译的安卓工程都是基于Gradle构建的。Gradle的灵魂就是Task。一般这些task 参与、干预项目的打包流程。因此我们自定义插件也可以自定义一些Task来干预项目的打包。 插件的应用场景? 接下来我们就回顾下安卓工程中的gradle插件场景,如下部分代码。是不是很熟悉又陌生,熟悉是因为你创建工程后、项目开 Android Gradle 插件 4.0 支持在 Gradle 构建配置中使用 Kotlin 脚本 (KTS),用于替代 Groovy(过去在 Gradle 配置文件中使用的编程语言)。将来,KTS 会比 Groovy 更适合用于编写 Gradle 脚本,因为采用 Kotlin 编写的代码可读性更高,并且 Kotlin 提供了更好的编译时检查和 IDE 支持。这里记录下,在修改 flavor时候,遇到的几个坑。 一、 在项目多渠道开发时,除了对不同的渠道除了做统计外,还可以对不同的渠道加载不同的代码及资源,具体的部署可以参考 Android studio gradle中分渠道加载res、libraries及Class ;在模块化拆分后,若恰好在模块内部的代码及资源也要根据不同的渠道发布不同的aar包到nexus仓库,该怎么配置呢? 二、思路:一般单独拆分出的library基本都是将代码及资源打包成aar... 直接编写是Android项目工程自带的默认管理方式,在每一个module中都写死了不同依赖及版本号,因此每次升级依赖库时都需要对每一个module做大量的手动更改。Google在Android官方文档中推荐通过使用gradle的extra属性,将依赖及版本号编写到config.gradle配置文件中,每个module都去依赖config.gradle中的版本,从而达到统一管理的目的。ext {libs = [Gradle文档。DependencyHandlerScope.of(dependencies).configuration()
这句代码,得出结论似乎是dependencies中有ext{}
于是乎赶紧把ext{}搬到了dependencies{}里面,经过测试能够正确加载依赖了!Wow~