为什么我们需要停止在 Gradle 中使用 buildSrc

这几天被 Intellij 语法无法高亮折磨得要死要活的我终于得到了解脱,回想起问题出现的时机,啊,没错,又是这该死的 buildSrc。

起因

出于对 Gradle 强制 Kotlin 版本的尊重,且我需要在 buildSrc 中引入 Kotlin Gradle plugin 的依赖。使用了 embeddedKotlin("gradle-plugin") 而不是 kotlin("gradle-plugin", "<version>")。于是整个项目持续出现 Syntax highlighting has been temporarily turned off in file xxx.kt because of an internal error,这极大的影响了我的开发效率。

发现与解决

在开发过程中,我发现 syncpublish 的操作都不会触发报错,而当我运行 build 的时候提示我二进制兼容存在问题,原因是用了不匹配的 Kotlin 版本。而这版本号引起了我的警觉。报错中出现的版本号竟然和 Gradle 内置的版本号一至,而非我在项目中使用的版本号。

经过一番代码搜索,我发现我只有在 buildSrc 中使用了它。于是我将其改为项目使用的 Kotlin 版本, Oh nice! 问题解决了。

正篇

说了那么多,不是说要丢掉 buildSrc 吗?

是的没错,接下来就说说为什么我们需要丢掉 buildSrc。

说实话,在 buildSrc 发布之初我是非常兴奋的。因为它相当于给项目打开了新世界的大门,使项目的 Gradle 脚本变得不再臃肿。同时我们也可以更方便的自定义 tasks。

但随着使用程度的深入,我发现 buildSrc 具有以下缺点:

  • 编译 buildSrc 的 tasks 都不支持缓存,这意味着每次修改 buildSrc 下的内容都需要重新全量编译。如果项目非常大的话,这将是一个非常痛苦的过程,大大影响了我们的开发效率。

  • 产生代码高亮问题(本篇开头所描述的)

但 buildSrc 的便捷性摆在那里,那么我们有什么解决办法吗?

答案是有的!!!

Composite build(复合构建)走上台前。

复合构建直接解决了上述提到的 buildSrc 的所有痛点。并且可以使我们开发出更多玩法。

如 Gradle 项目自身的源码就使用了在根项目(rootProject)和 build-logic 中都将 build-logic-commons 以复合构构建的形式引入。详情可以自行查看 Gradle 的源码。

结语

关于复合构建其实很多东西没有细说,因为我认为其实代码比起文章,更容易描述出我们实际应该如何运用。感兴趣的话可以参考我列出的以下几个项目来深入进行学习:

入门级:
https://github.com/Omico/gradle-issue-missing-kotlin-dsl-in-settings
https://github.com/square/wire

稍微复杂:
https://github.com/android/nowinandroid
https://github.com/Omico/age
https://github.com/Omico/Gradm

大师级:
https://github.com/gradle/gradle