记一次个人项目迁移到 AGP 8.0+ & Gradle 8.0+ 的全过程

9,372 阅读5分钟

前言

历经几个月的拖延,我终于在今天下午决定将自己的项目从 AGP 7.1.2 & Gradle 7.3.3 迁移至 AGP 8.0+ & Gradle 8.0+。整体过程还算顺利,但也遇到了一点问题,结果也比较有意思。本文就记录下迁移的过程。

开始

基本迁移

关于提升 AGP 版本,AS 内置了 AGP Upgrade Assistant,可以快速处理一些必要的变更。因此先拿它跑一下。

打开后选择目标版本,上面会清晰地列出将作出的变更。如果你发现 “Run selecyed steps” 按钮为灰色,那么可以查看左侧列表中是否有警告项,有的话可以按上面的提示先修复。之后点击按钮,开始跑 image.png

运行的过程还算顺利,在下载了一波相关依赖后,我们的项目终于……同步失败了~ 好吧,这也正常,看看报了啥错

compileDebugJavaWithJavac' task (current target is 1.8) and 'kspDebugKotlin' task (current target is 17) jvm target compatibility

顺带附了个链接:Configure a Gradle project | Kotlin Documentation ,打开一看,嚯,原来是 Java 版本不一样的问题

image.png

AGP 8.0 要求 JDK 17,这也是 Android Studio F 版本自带的 JDK 版本。

上面写到的解决方法有两种,一是升级 AGP,二是手动改。作为懒人,先试试第一条路?

尝试再次升级 AGP

打开 Maven 仓库搜一搜(Maven Repository),发现竟然都出到 8.2.0-alpha 了。不敢用不敢用,还是换个 8.1.0-beta 试试吧

image.png

更改版本,重新 sync …… 然后,有意思的事情来了,AS F 还不支持这个 AGP 版本,必须得 G 及以上才行

image.png

image.png

AS 与 AGP 版本对应关系

鉴于我的项目是开源的,要是再要求 AS 必须得是预览版的,这运行要求也太高了。所以还是换第二条路吧

手动指定

手动设置一下 Java 语言版本和 Kotlin 编译的目标版本

我直接一个全局替换,把两项都指定为 Java 17

compileOptionjvmTarget
image.pngimage.png

至此,应用终于可以正常编译了。到这里的所有变化可以看 这个 Commit,其中大部分为 AGP Upgrade Assistant 自动完成的。

当然,迁移到这里还没有结束,如果查看 gradle.properties 的内容,会发现它为了平滑过渡,其实很多设置仍然保留的与之前相同,这里或许我们还可以改进一下

修改 Gradle.properties

先看看 AGP Upgrade Assistant 帮我们改了哪些内容

image.png

接下来我们一条一条看

buildconfig

如果你调用模块代码中的 BuildConfig 类,你需要在你的模块的 build.gradle.kts 文件中,在 android {} 块中启用 buildConfig。否则,BuildConfig 文件不再自动生成。

BuildConfig 文件是一个 Java 文件,包含关于当前构建的静态信息,例如命名空间名称、flavor 名称、调试标志等等。以前 AGP 总是为所有 Android 模块生成 BuildConfig 文件。如果你开发一个多模块应用程序,你可能会得到许多 AGP 需要处理的 BuildConfig 文件,这会影响你的构建速度。然而,大多数模块不需要从 BuildConfig 类中获取任何信息。

此外,BuildConfig 是一个 Java 文件。假设你的应用程序是用 Kotlin 编写的,在同一模块中混合 Java 和 Kotlin 会进一步影响构建性能。为了缓解这个问题,我们引入了设置在 gradle.properties 中的 android.enableBuildConfigAsBytecode 标志。当 android.enableBuildConfigAsBytecode=true 时,BuildConfig 文件不再生成为 Java 文件,而是生成为编译文件。这避免了 Java 编译步骤!

我看了下我的代码,确实只有很少的模块用到了 BuildConfig。因此将其值改回 false,并在需要 BuildConfig 的模块中添加:

image.png

nonFinalResIds

这个主要影响 Java 代码,具体来说,如果设置为 true,那你的 switch-case 里就不能写 id 了,因为它不是 final 的值。如下:

image.png

但我这个项目是 Kotlin + Jetpack Compose 的,完全不存在这个问题,因此设为 true 也没问题

nonTransitiveRClass

非传递R类,启用后,主工程不再合并 lib 库的 R 文件了,有助于加速编译。如果主工程用了子工程的资源,那引用 R 的写法都要变更下,需要加上完整的类名

AS 提供了一键迁移的按钮,点击后可以预览变更,一键处理

image.png

具体来说,处理后会变成这样:

image.png

(我才发现引用资源引用错了,怎么跑去使用别人家的库里面的资源了,汗)

至此,上面新增的三项配置项都可以使用默认值了。 到现在,debug 包可以正常运行了。然而,当我尝试 release 包时,它不出意外的报错了……

适配 Release 包

报的什么错呢?如下:

Missing classes detected while running R8. Please add the missing classes or apply additional keep rules that are generated in D:\projects\AppProjects\Mine\FunnyTranslation\translate\build\outputs\mapping\release\missing_rules.txt.

打开这个文件看一下,内容如下:

# Please add these rules to your existing keep rules in order to suppress warnings.
# This is generated automatically by the Android Gradle plugin.
-dontwarn java.awt.AWTEvent
-dontwarn java.awt.ActiveEvent
-dontwarn java.awt.BorderLayout
-dontwarn java.awt.Color
-dontwarn java.awt.Component
-dontwarn java.awt.Container
-dontwarn java.awt.Dimension
...

按第一行的提示,把里面的内容加入 proguard-rules,重新打包,一切 OK

顺带一提,我关闭了 AGP 8.0 默认的 R8 full 模式,也就是

android.enableR8.fullMode=false

如果开启了 fullMode,则 R8 将更加激进,具体可以参考:R8 FAQ

到此的变更可以见 这里

变化

折腾了一通,最后效果是啥呢?
编译速度方面,按理说应该能提高一定的编译效率,更高地命中缓存。但这个忘记测量之前的数据了,就先不谈。

至于体积方面……一顿操作猛如虎,一看体积涨了五??!

image.png

image.png

当时我啪的一声站起来了,很快啊,这个 AGP,啊~,不讲武德,来骗,来偷袭,我 20 岁的小同志,这好吗?这不好。我去!我劝,好好反思,不要再耍这样的聪明,小聪明啊……

参考

本文源代码见:此处