虾扯淡
很多人都介绍过Gradle 7.+
提供新依靠办理工具VersionCatalog
,我就不过多介绍这个了。咱们最近也算是成功接入了VersionCatalog
,进程也仍是有点弯曲的,总体来说我觉得确实比咱们当时的ext,或许说是用buildSrc的形式进行依靠办理是个更老练的计划吧。下面是几个介绍的文章,特别能够看看三七哥哥的。
Android 依靠办理及通用项目装备插件
【Gradle7.0】依靠一致办理的全新方式,了解一下~
之前大部分文章只介绍了技能计划,很少会去横向比照几个技能计划之间的好坏。从咱们最近一个月的运用成果上来看吧,接下来我给咱们剖析下实践的好坏,仅仅只代表个人看法, 上表格了。
由于
VersionCatalog
运用的文件格式是toml
,所以后续或许会用toml
进行简称。
ext | buildSrc | toml | |
---|---|---|---|
声明域 | *.gradle | *.java *.kt | *.toml |
可修正 | 可修正 | 不行修正 | 不行修正 |
写法 | 花里胡哨 | 静态变量 | 固定写法 xxx.xxx.xxx |
校验 | 随意写 | 编译时校验 | 同步时校验 |
声明域: 指的是咱们在哪里声明这些依靠办理。其间ext能够在绝大部分的.gradle
中去进行声明,所以就会导致依靠声明的过于零星。而这部分问题就不存在于buildSrc和toml中,他们只能被声明在固定的方位上。
可修正性: 特制声明的依靠能否被修正,ext声明是在内存空间内,而ext的本质其实便是一个Any
他能够存放恣意的东西,假如呈现同名的则会是后面声明的把前面声明的覆盖掉,这便是一个十分不安稳的特点,而buildSrc则是由class来声明的,咱们没有方法在gradle中去修正这部分,所以相对来说是安稳的。而toml
也相似,根据固定格式反序列化成代码。不具备修正的才能。
写法: ext这方面是真的拉胯,比方支持libs.abc
或许libs."abc"
或许libs.["abc"]
还能够单引号,就十分的随意,并且极为不一致。这也是咱们本次改动中碰到问题最多的时分。其他两种写法都相比照较固定,相似java/kt 中的静态常量。
校验: ext便是爱咋写咋写吧,横竖也没有很好的校验啥的。而buildSrc则是根据java的代码编译来的,toml由于是一个新的文件格式,所以内置了一套相比照较强的语法校验,假如不合规矩会报错,并显现过错行数。
听说buildSrc对于增量编译的适配等其实不太良好,并且咱们是一个复杂的巨型复合构建的工程,所以个人并不太推荐buildSrc。
能够参考这篇文章第二章 Stop using Gradle buildSrc. Use composite builds instead
由此可证哦,VersionCatalog
雀食是一个十分好的选择,特别假如你们当时仍是在运用的是ext的情况下。
巨型工程最费事的事情其实别的一点便是技能栈的切换,由于要改起来的地方可真的便是太多了,首要便是要先处理复合构建的情况下大局只有一份注册的逻辑,其二便是把当时工程的ext悉数转移到toml中,然后要最好和之前的方式挨近,尽量保证最小改动。最终则是一切工程都改一下!!!!!!!!(要我狗命)
同享装备
GradleSample demo 工程如下,其间plugin-version便是
咱们也采取了之前Gradle 奇淫技巧之initscript pluginManagement一样的方式,经过initscript
做到复合构建内同享插件的才能。
别的咱们把VersionCatalog
作为一个extension
抛出来在外部完结注册。
catalogs {
script = new File(rootProjectDir, "depencies.gradle")
versionCatalogs {
create("libs") { from(files("${rootProjectDir.path}/toml/dependencies.versions.toml")) }
create("module") { from(files("${rootProjectDir.path}/toml/module.versions.toml")) }
}
dependencyResolutionManagement {
repositories {
maven { setUrl("https://maven.aliyun.com/repository/central/") }
maven {
setUrl("https://storage.googleapis.com/r8-releases/raw")
}
gradlePluginPortal()
google()
mavenLocal()
maven {
url "https://dl.bintray.com/kotlin/kotlin-eap"
}
}
}
}
经过这部分装备就能够把同享的部分注入进工程内。然后便是很沙雕的改改改了,把一切的ext悉数迁移到咱们新的toml上去,然后注册出多个。
命令行工具
TheNext 虾开发的撒币cli工具 专门处理虾的撒币问题
曾经也说过了咱们工程的模块数量巨大,然后又由于ext的写法风骚,所以咱们基本一切的写依靠的地方都要改,便是真的工作量巨大。
一个优秀的摸鱼工程师最重要的天赋便是要学会转化生产力,把这种简略又繁琐的工作交给命令行来处理。所以这就有了TheNext
的一个新才能,根据当时的文件目录修正一切的.gradle
文件,然后把非标准的ext的写法悉数进行一次替换。

作用如图所示。
代码逻辑如下,咱们首要会遍历整个工程的文件目录,然后发现.gradle
后缀的文件,之后经过正则匹配出dependencies
,然后进行把一些"" '' []
等等都删掉,然后把- _
更换成.
,这样就能完结简略的主动替换了。
package com.kronos.mebium.android
import com.beust.jcommander.JCommander
import com.kronos.mebium.action.Handler
import com.kronos.mebium.entity.CommandEntity
import com.kronos.mebium.file.getRootProjectDir
import com.kronos.mebium.utils.green
import com.kronos.mebium.utils.red
import com.kronos.mebium.utils.yellow
import java.io.File
import java.util.Scanner
/**
*
* @Author LiABao
* @Since 2022/12/8
*
*/
class DependenciesHandler : Handler {
val scanner = Scanner(System.`in`)
var isSkip = false
override fun handle(args: Array<String>) {
isSkip = args.contains(skip)
val realArgs = if (isSkip) {
arrayListOf<String>().apply {
args.forEach {
if (it != skip) {
add(it)
}
}
}.toTypedArray()
} else {
args
}
val commandEntity = CommandEntity()
JCommander.newBuilder().addObject(commandEntity).build().parse(*realArgs)
val first = commandEntity.file
val name = commandEntity.name
val root = first
val files = root.walkTopDown().filter {
it.isFile && it.name.contains(".gradle")
}
val overrideList = mutableListOf<Pair<File, File>>()
files.forEach {
onGradleCheck(it)?.apply {
overrideList.add(it to this)
}
}
confirm(overrideList)
}
private fun confirm(overrideList: MutableList<Pair<File, File>>) {
if (overrideList.isEmpty()) {
return
}
println("if you want overwrite all this file ? input y to confirm \r\n".red())
val input = scanner.next()
if (input == "y") {
overrideList.forEach {
it.first.delete()
it.second.renameTo(it.first)
}
print("replace success \r\n ".green())
} else {
print("skip\r\n ".yellow())
}
}
private val pattern =
"(\\D\\S*)(implementation|Implementation|compileOnly|CompileOnly|test|Test|api|Api|kapt|Kapt|Processor)([ (])(\\D\\S*)".toPattern()
private fun onGradleCheck(file: File): File? {
var override = false
val lines = file.readLines()
val newLines = mutableListOf<String>()
lines.forEach { line ->
val matcher = pattern.matcher(line)
if (matcher.find()) {
val libs = matcher.group(4)
if (!libs.contains(":") && !libs.contains("files(")) {
val newLibs =
libs.replace("\'", "").replace("\"", "").replace("-", ".").replace("_", ".")
.replace("kotlin.libs", "kotlinlibs").replace("[", ".").replace("]", "")
if (newLibs == libs) {
newLines.add(line)
return@forEach
}
print("fileName: ${file.name} dependencies : $line \r\n")
if (isSkip) {
override = true
newLines.add(line.replace(libs, newLibs))
print("$libs do you want replace to $newLibs \r\n ".green())
return@forEach
}
print("$libs do you want replace to $newLibs ? input y to replace \r\n ".red())
while (true) {
val input = scanner.next()
if (input == "y") {
print("replace success\r\n".green())
override = true
newLines.add(line.replace(libs, newLibs))
return@forEach
} else {
print("skip\r\n ".yellow())
break
}
}
}
}
newLines.add(line)
}
if (override) {
val newFile = File(file.parent, file.name.removeSuffix(".gradle") + ".temp")
newLines.forEach {
newFile.appendText(it + "\r\n")
}
return newFile
}
return null
}
}
const val skip = "--skip"
代码就基本是这样,假如有正则带佬能够帮忙优化下正则的。
然后这个工具也能够多次复用,由于我这个需求没有方法很快的被合入,需要频繁的rebase master的代码,每次rebase完之后都要进行二次修正,真的吐了。
验收
每个新功能开发最终都是要进行验收的,特别是技改需求,你到时分把功能搞坏了到时分可是要背黑锅的啊。并且这种需求也没有方法要求测验进行特别系统性的测验,所以仍是要开发自己想方法了。
咱们拉取了apk包的依靠,然后用HashSet进行了拉平,去除重复依靠,然后经过diff比照前后差异,在基本符合预期的情况下咱们就能够进行快速的合入。
结束
其实本文的中心是给咱们剖析下几种依靠办理方式的好坏,然后对于还在运用gradle ext
的大佬,其实能够逐步考虑进行替换了。
最终祝咱们新年快乐了,兔年大吉吧!