Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17
随着 Android Studio Flamingo 正式版的发布,AGP 8(Android Gradle Plugin 8)也正式进入大家的视野,这次 AGP 8 相关更新属于「断代式」更新,同时如果想体验 AGP 8,就需要升级到 Android Studio Flamingo 版本,而升级到 Flamingo 的话,默认自带的 Java 版本就会变成 JDK 17 ····· 所以,这就是你需要适配 AGP8 的主要原因之一。
Flamingo 兼容
首先,如下图所示,使用 Flamingo 不一定就要用 AGP 8,它的支持范围是 3.2- 8.0
,但是,因为 Flamingo 默认自带的 Java 版本是 JDK 17 ,所以默认情况下你最低需要 AGP 7 。
为什么 Flamingo 默认情况下只能用 AGP 7 ?
如下图1所示,是 Gradle & Java 的版本对照表,可以看到 Gradle 7.3 是第一个支持 Java 17 的 Gradle 版本,而根据图2 Gradle 和 AGP 的版本对应关系,AGP7.2 开始所需最低 Gradle 版本就是 7.3.3,所以一般情况下建议 Flamingo 使用 AGP 7.2 和 gradle-7.3.3 。
![]() | ![]() |
---|
当然,这里写了所需最低版本,所以你也可以用 AGP 7.0 搭配 gradle-7.3 运行,我有的项目就是使用了
build:gradle:7.0.3
/distributions/gradle-7.3-bin.zip
来适配 Flamingo。
另外,你也可以通过修改环境变量和 Android Studio 里的配置来使用低版本的 JDK ,例如通过 Project Structure
- Gradle Settings
- Gradle JDK
来选择外部 JDK 版本,通过降低 JDK 版本来支持更低的 AGP 版本。
最后,Gradle 版本还和 Kotlin 版本有关系,根据你使用的 Gradle 版本也需要配置对应的 kotlin-gradle-plugin
版本。
所以这里可以简单先总结一下:
- 要使用 AGP 8 需要 Android Studio Flamingo
- Android Studio Flamingo 自带 JDK17 ,默认情况下最低需要
build:gradle:7.2
/distributions/gradle-7.3.3-bin.zip
,兼容下可以build:gradle:7.0.3
/distributions/gradle-7.3-bin.zip
- 通过配置使用外部 JDK 可以降低 AGP 的版本要求
是不是觉得现在 Android Studio 和 Gradle/Kotlin 关系捆绑得越来越紧密?
AGP 8
对于一些人而已,可能 7 还没用过,8 就又来了,但是 AGP 8 又属于「半断代式」更新,所以还是有需要适配一下。
AGP Upgrade Assistant
一般情况下我建议使用 AGP Upgrade Assistant 来先自动处理升级 ,可能还有一些人不知道什么是 AGP Upgrade Assistant ,其实就是你启动 Android Studio 的时候,右下角经常会弹出的提示框,也可以通过 Tools
- AGP Upgrade Assistant
去打开。
![]() | ![]() |
---|
如今的 AGP Upgrade Assistant 已然不是曾经的傻瓜式工具,它已经长大了。
如下图所示,如今的 AGP Upgrade Assistant 已经相当成熟, AS 会根据你当前的 AGP 版本,为你罗列出可以升级的 AGP 版本进行选择,同时你可以根据需要勾选迁移的选项,然后 Assistant 会根据你的选择自动调整你当前配置,这对于一些模块较多的项目在迁移时可以节省很多时间。
DSL 支持 namespace
说到 AGP8 适配,首先必提的就是 namespace 的适配需求,升级到 AGP 8 之后,在 Gradle Sync 的时候你可能会到类似的错误提示 :Namespace not specified
,这是因为 AGP 开始强制要求 namespace 配置。
其实 AGP 7 开始就是有 namespace 配置,而 AGP 8 开始强制要求。
谷歌这次是希望通过 namespace
来让 package
属性得到释放,特别对于 Module 结构来说, namespace
更贴合认知逻辑,而不会像 package
一样还“夹带”了 applicationId
的属性。
namespace 也和后续的 R id 有关联。
如下图所示是需要调整的逻辑,主要就是移除了 Manifest 文件下的 package
属性 ,然后增加了 build.gradle 文件下的 namespace
配置,这一步推荐使用 AGP Upgrade Assistant 自动迁移,特别是对于 Module 比较多的项目,可以解放大量重复劳动。
默认参数调整
如下图所示,AGP 8 里一些默认配置参数进行了调整,基本上这部分也是导致项目升级 AGP 8 跑不起来的「元凶」之一。
当然,如果你是使用 AGP Upgrade Assistant 进行升级迁移的话,一般情况下 Assistant 会根据你的项目情况自动进行适配,如下图就是 Assistant 在升级迁移时在 gradle,properties
下自动新增的部分。
buildfeatures.buildconfig
如果你需要在 Module 代码里调用 BuildConfig
,那么现在你需要如下代码所示一样配置 buildConfig
:
android {
buildFeatures {
buildConfig = true
}
}
或者直接在 gradle,properties
里全局配置
android.defaults.buildfeatures.buildconfig=true
另外,如果是需要在 Kotlin 里使用 BuildConfig
,还可以配置 BuildConfigAsBytecode
来提高编译速度:
android.enableBuildConfigAsBytecode=true
nonTransitiveRClass
nonTransitiveRClass 也是存在已久的属性,简单来说就是配置非传递性 R 类 ,以前也有人用它来解决资源冲突,因为 nonTransitiveRClass 会强制要求 Module 的资源按 namespace 来区分使用。
由于这次默认值变成 true,所以如果不想弃用,可以在 gradle,properties
下配置为 false 。
android.nonTransitiveRClass=false
当然,你也可以通过 Android Studio 的自动化迁移工具来完成,毕竟这部分主要是涉及 namespace 声明而已,官方的自动化脚步处理还是挺方便的。
处理后也就是从 R 变成了 xxxxxx.xxxx.xxx.R 的效果:
nonFinalResIds
升级到 AGP8 ,你可能会看到一个错误: Resource IDs will be non-final
,这个问题主要出现在使用 switch
下的 R.id
场面,这个问题如果是没了解过,可能第一眼看到会觉得蒙圈,为什么不能用 R.id
了?
解决问题的最简单方式就是使用配置 nonFinalResIds
为 false ,或者你将 switch
修改为 if
,其实我个人建议还是直接关闭 nonFinalResIds
来的实际,毕竟一对 if 还是很难受的。
android.nonFinalResIds=false
enableR8.fullMode
这是一个很有意思的配置,R8 我记得应该是从 Android Studio 3.3 就存在,简单来说,R8 是一站式处理代码压缩(或 tree-shaking),资源缩减、混淆和优化的过程,一个官方定义比 Proguard 更快且压缩更好的配置。
默认情况下 AGP 3.4 开始 R8 就是默认编译器,但是它还是会使用 ProGuard 文件来修改其默认行为,此时的 R8 是普通模式,也就是之前的 android.enableR8=true
配置,普通模式是兼容 Proguard的,所以用户基本无感。
但是 AGP8 开始 R8 默认是 fullMode
,R8 的 fullMode
会自动处理一些常见的混淆规则,但它比普通模式优化更激进,例如:
你只通过 Java 反射 API 引用了一个类,
fullMode
下 R8 会觉得你的代码在运行时从不使用这个类,它会直接从 DEX 中删除该类。
当然,如果你的项目里 keep 规则是完整的,例如反射使用的所有内容都包含在 keep 规则中,那么 fullMode
应该不会引起什么问题,但是,如果你不希望它工作,那么配置 fullMode
为 false 也是可以的
android.enableR8.fullMode=false
所以适配 fullMode
的主要精力在于针对反射部分的混淆适配,因为如果一不注意,反射部分的 class 在 dex 里就会被 R8 删除。
另外,要输出 R8 在构建项目时应用的所有规则完整报告,可以在 proguard-rules.pro
添加:
// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt
Plugin 适配
AGP 8 里正式移除了 Transform API 并通过 Artifacts API 和 Instrumentation API 来缩短构建时间 ,在此之前,我们一般通过 Transform API 在编译后的 class 文件转换为 dex 文件之前一些自定义打桩处理,而 AGP 8 开始,为了提高构建性能,使用 Transform API 很难与 Gradle 的其它特性结合,所以本次正式移除 Transform API ,这是一些第三方插件需要适配的地方。
另外,在做 Maven 发布的时候,需要添加对应的 singleVariant
来支持 publications
的兼容,虽然这不是 AGP 8 才开始的,但是也算是需要适配的点之一。
最后
AGP 8 和 Flamingo 需要兼容的问题大致就这样,可以看到 Android Studio 和 Gradle/Kotlin 关系捆绑得越来越紧密,如果不了解它们的依赖关系,处理器兼容就会迷失方向。
另外 AGP 现在的每个大版本变动也很大,比如前面没有特别介绍的 aidl
和 renderscript
配置位,下个大版本应该就会被移除了,只能说 Gradle 真的就是为了「折腾」而生。
如果你还有什么问题,欢迎评价交流。
转载自:https://juejin.cn/post/7238978524031123515