gradle迁到kts, 以及module管理
github blog
qq: 2383518170
wx: lzyprime
λ:
仓库地址: https://github.com/lzyprime/android_demos
本来想把compose
版本分离成单独分支:dev_compose
; 但是后来发现与dev
分支除了view
层不太一样,剩下的全是同样代码;甚至view
层一些compose
组件也全是一样的。
model
层里,对数据组织和封装在频繁的改动,想找到更合理易用的方式,比如对DataStore
的提供和使用方式,已经调整过好几版,目前的仍不是满意版本。
如果两个分支,这部分代码同步就很烦人。git sub module
, git rebase
, 手动复制。哪一个都不方便。
所以,把view
以外公用的部分,抽成单独的gradle module
, compose
的view
部分也抽成一个module
。然后在gradle
脚本里配好依赖关系。
gradle kts
gradle 官网文档
android 官网迁移文档
迁移完发现android
官网文档居然也提了这事。
好处
- 相比
groovy
, 对kotlin
更熟悉。脚本易读性提高,对脚本中每一步在执行什么,什么意思更容易掌握,点开看源码和注释。 - 更规范,去糖。
groovy
为了脚本编写便捷,提供了一堆简便写法,而很多其实是靠字符串解析,看是否符合规则,然后去调用真正的接口。 - 接口废弃等提醒。
gradle
即将废弃接口,接口警告信息等等,都会向kotlin
代码一样,直接突出显示。 - 用
KTS
版本去学习gradle
的用法。之后就算是groovy
版本的,也能看个大概,看着官网文档和基础语法也能写的差不多。可能简便写法不怎么会,但是中规中矩的脚本能跑应该没问题。
坏处
- 相比
groovy
, 肯定还是简陋,不完善。包括文档里,常常会有只支持groovy
的提示。
迁移过程
gradle 迁移文档
给gradle脚本
文件名加上.kts
后缀(如build.gradle -> build.gradle.kts
), 然后sync
一下, 解决所有报错。每次最好只改一个文件,否则报错难修。
- 字符串必须全是双引号
- 函数调用加括号。如
classpath
,implementation
等等后面空格加字符串的,一般是函数调用。改成classpath(xxx)
样式 - 属性值,如
minSdk
,targetSdk
,versionCode
等等被做成了属性。同时如果属性为bool
类型,名字会变成isXXX
的形式。 tasks
,ext
,extra
,buildSrc
tasks
每个task
, 包含name:String
, args:Map
,configureClosure: Function
. groovy
提供了一堆简便写法,但最终肯定归到这三部分。以task clean
为例。
// groovy
task clean(type: Delete) {delete rootProject.buildDir
}
如果点进去,会发现批到的是task(name:String)
,后边部分都会当字符串处理。这就是groovy
提供便捷写法的方式之一,字符串解析。最后相当于:
// 伪代码
task(args: {"type": Delete::class}, name: "clean", configureClosure: { // Deletedelete(rootProject.buildDir)},
)
的确简便写法够简洁形象,就像声明一个函数。可是不看源码之类的,谁知道是什么。
kotlin
也提供了一堆简便写法,以incline function
的形式,可以一层层点到最后。
gradle 任务文档
ext
问题
KTS
也有 ext
函数,但如果像之前在buildScript
块里写,就会报错。点进去就知道原因:
val org.gradle.api.Project.`ext`: org.gradle.api.plugins.ExtraPropertiesExtension get() =(this as org.gradle.api.plugins.ExtensionAware).extensions.getByName("ext") as org.gradle.api.plugins.ExtraPropertiesExtensionfun org.gradle.api.Project.`ext`(configure: Action<org.gradle.api.plugins.ExtraPropertiesExtension>): Unit =(this as org.gradle.api.plugins.ExtensionAware).extensions.configure("ext", configure)
也就是尝试把当前对象转为ExtensionAware
。在groovy
中,buildScript
是Project
的方法,Project
实现了ExtensionAware
接口。在KTS
里,buildScript
来自KotlinBuildScript
抽象类, 是个ProjectDelegate
,用委托的方式访问Project
, 往上找基类也的确是Project
。
但是buildScript
函数接收的是操作ScriptHandlerScope
类型。
@Suppress("unused")
open fun buildscript(@Suppress("unused_parameter") block: ScriptHandlerScope.() -> Unit): Unit =internalError()// use:
buildscript { // this: ScriptHandlerScope...
}
也就是说,代码块里的 this
是个 ScriptHandlerScope
, 并没有实现ExtensionAware
。 所以ScriptHandlerScope as ExtensionAware
失败了。
这也是为什么ext
在顶级块里写或者在allprojects
块里可以正常工作:
buildScript {...}// this: ProjectDelegate
ext {set("key", "value")
}allprojects { // this: Projectext {set("k", "v")}
}tasks.register<Delete>("clean") {rootProject.ext["key1"] // 指定Projectdelete(rootProject.buildDir)
}
但这只是定义的时候,使用的话,同样因为这种限制,要看清楚作用域,是否能转为ExtensionAware
,还要搞清楚是谁的。
同时受kotlin
静态语言的限制,想直接Project.ext.key1
, 甚至Project.key1
使用,是不可能的。就得Project.ext["key1"]
。
tasks.register<Delete>("clean") {val key1 = rootProject.ext["key1"] // 指定Projectdelete(rootProject.buildDir)
}
但是在buildScript
里这么写又过不去。此时通过ExtensionAware.extentions.getByName("ext")
还拿不到。其实在groovy
中也是点不进去的,可以看看groovy
怎么处理的,怎么达到动态语言的效果。
ext
-> extra
所以这东西基本就废了。然后提供了extra
。
buildscript {val gradleVersion by extra("7.0.1")val kotlinVersion by extra{ "1.5.21" }extra["activityVersion"] = "1.3.1"extra["lifecycleVersion"] = "2.3.1"
}// module project
val kotlinVersion: String by rootProject.extraval activityVersion: String by rootProject.extra
val lifecycleVersion: String by rootProject.extra
如果通过委托属性的方式获取值。需要显式声明类型。源码:
val ExtensionAware.extra: ExtraPropertiesExtensionget() = extensions.extraProperties
也就是说,其实和ext
拿到的是一样的,Project.ext
其实就是在把ExtensionAware.extensions.extraProperties
抛出去。
所以基础的set get
等仍然好使。额外添加了一堆委托属性和函数,方便创建获取变量。
val kkk by extra(vvv)
:
// val kkk by extra(vvv)
operator fun <T> ExtraPropertiesExtension.invoke(initialValue: T): InitialValueExtraPropertyDelegateProvider<T> =InitialValueExtraPropertyDelegateProvider.of(this, initialValue)// InitialValueExtraPropertyDelegateProvider(extra, vvv)class InitialValueExtraPropertyDelegateProvider<T>
private constructor(private val extra: ExtraPropertiesExtension,private val initialValue: T
) {companion object {fun <T> of(extra: ExtraPropertiesExtension, initialValue: T) =InitialValueExtraPropertyDelegateProvider(extra, initialValue)}operator fun provideDelegate(thisRef: Any?, property: kotlin.reflect.KProperty<*>): InitialValueExtraPropertyDelegate<T> {// 插入, 变量名(kkk) 作为keyextra.set(property.name, initialValue)return InitialValueExtraPropertyDelegate.of(extra)// InitialValueExtraPropertyDelegate(extra)}
}class InitialValueExtraPropertyDelegate<T>
private constructor(private val extra: ExtraPropertiesExtension
) {companion object {fun <T> of(extra: ExtraPropertiesExtension) =InitialValueExtraPropertyDelegate<T>(extra)}// 赋值操作。 kkk = nvvv -> extra.set(kkk, nvvv)operator fun setValue(receiver: Any?, property: kotlin.reflect.KProperty<*>, value: T) =extra.set(property.name, value)// 取值操作。val nk = kkk -> val nk = extra.get(kkk)@Suppress("unchecked_cast")operator fun getValue(receiver: Any?, property: kotlin.reflect.KProperty<*>): T =uncheckedCast(extra.get(property.name))
}
中规中矩的委托。val kkk: T by extra
也是一样:
operator fun ExtraPropertiesExtension.provideDelegate(receiver: Any?, property: KProperty<*>): MutablePropertyDelegate =if (property.returnType.isMarkedNullable) NullableExtraPropertyDelegate(this, property.name)else NonNullExtraPropertyDelegate(this, property.name)private
class NonNullExtraPropertyDelegate(private val extra: ExtraPropertiesExtension,private val name: String
) : MutablePropertyDelegate {override fun <T> getValue(receiver: Any?, property: KProperty<*>): T =if (!extra.has(name)) cannotGetExtraProperty("does not exist")else uncheckedCast(extra.get(name) ?: cannotGetExtraProperty("is null"))override fun <T> setValue(receiver: Any?, property: KProperty<*>, value: T) =extra.set(property.name, value)privatefun cannotGetExtraProperty(reason: String): Nothing =throw InvalidUserCodeException("Cannot get non-null extra property '$name' as it $reason")
}
getValue
, setValue
是根据变量类型做类型转换。所以要写类型,还要写对。
buildSrc
kotlin dsl plugin 文档
另外完成共享的方式。在rootProject
目录下创建buildSrc
文件夹,并创建build.gradle.kts
。
/
|-buildSrc|- src/main/kotlin/xxx.kt|- build.gradle.kts
//buildSrc/build.gradle.kts
plugins {`kotlin-dsl`
}repositories {mavenCentral()
}
src/main/kotlin
下的内容在工程内共享。所以可以把变量定义在这:
// src/main/kotlin/versions.kt
const val kotlinVersion = "1.5.30"
...
其他地方可以直接用。
好处是往gradle
添加附加功能更方便,易于管理。
弊端就是变量如果放在这,IDE可视化的Project Structure识别失败,就会一直提示有内容可以更新。
module 管理
没什么可讲的。new 一个 module。 根据需要选择类型。然后就是build.gradle.kts
处理好依赖和构建。settings.gradle.kts
中include
。
当 A_module 依赖 B_module:
// A_module build.gradle.kts
dependencies {implementation(project(":B_module"))
更多具体操作可以看文档。转成KTS
不就是为了文档读着更容易。
gradle迁到kts, 以及module管理相关推荐
- Android Studio Gradle打包实践之多渠道+版本号管理
上次介绍了 Android Studio的安装.配置和基本使用 .这次讲一下Android Studio用到的打包工具Gradle. Gradle 是一种构建项目的框架,兼容Maven.Ant,为Ja ...
- Android Studio的Gradle常用命令配置和依赖管理
一,gradlew常用命令 ./gradlew -v 版本号 ./gradlew clean 清除工程目录下的build文件夹 ./gradlew build 检查依赖并编译打包 这里注意的是 ./g ...
- gradle第三方Jar包依赖统一管理
1. 背景 一个gradle的工程中往往包含很多的子工程,每个子工程都有其自己的Jar包依赖.现实情况是各个子工程对jar包的引入都是比较随意的,版本号各式各样,如何统一各个子工程的版本号?统一管理第 ...
- 打卡学习Gradle深度解析 - kts脚本加载流程
kts脚本加载流程 和groovy脚本一样,kts脚本也分为2个阶段 stage 1 执行buildscript和plugins部分,执行结果会对stage2 program的classpath有影响 ...
- gradle引入子module配置_原创 | 看完此文,你对Gradle的理解又升级了
前言 这一篇来介绍一些Gradle进阶的内容,当然进阶内容非常多,这篇文章就总结一些相对重要的.常用的一些知识点,比如Gradle的签名配置和依赖管理. 1.Android签名文件配置 在一般公司中, ...
- linux gradle目录结构,android studio中,project和module的目录结构
project.iml--NO:这个是用来管理project的相关配置信息的,也是标识这个文件夹是一个android项目的.如果误删该文件,Android Studio将不会将该文件当做安卓项目,只会 ...
- Gradle 2.0 用户指南翻译——第五十章. 依赖管理
本文禁止w3cschool转载! 翻译项目请关注Github上的地址:https://github.com/msdx/gradledoc . 本文翻译所在分支:https://github.com/m ...
- Gradle 1.12用户指南翻译——第五十章. 依赖管理
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- kts代替gradle升级指南高阶玩法
1.整体拦截自定义版本号渠道名编译时间.apk 2.整体拦截所有模块字符串加密 查看全文 http://www.taodudu.cc/news/show-5962886.html 相关文章: Kotl ...
最新文章
- java程序中的图片与数值关联_Java从图片中读取图片的元数据Exif信息
- 与基础事务管理器通讯失败
- mysql复杂连接查询语句_MySQL查询语句之复杂查询
- 愈学习愈发现自己的无知
- Spring定时任务注解@Scheduled+@EnableAsync用法详解(简单说明+应用场景+demo源代码+执行过程分析)
- OpenCASCADE:要求
- Colored Sticks--POJ 2513
- 【Eviews】第九周实验-二次/对数拟合、预测
- 6、oracle数据库下查询操作
- java 线程池 固定大小_使用Executors服务在Java中创建固定大小线程池的最佳方法...
- UVa 674 - Coin Change
- centos中,tomcat项目创建文件的权限研究
- 深搜和广搜--原理彼此的优缺点
- MFC框架下-调通官方demo以及如何使用SDK进行项目开发
- VIVADO 下载mcs 文件
- Matlab 多行屏蔽或注释方法
- Unity实现键鼠控制立方体移动旋转
- 网络爬虫——票房网数据抓取及MYSQL存储
- flvplayer.swfnbsp;flv视频播放器…
- 微服务开发中的数据架构设计 1