likes
comments
collection
share

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

作者站长头像
站长
· 阅读数 20

随着 Android Studio Flamingo 正式版的发布,AGP 8(Android Gradle Plugin 8)也正式进入大家的视野,这次 AGP 8 相关更新属于「断代式」更新,同时如果想体验 AGP 8,就需要升级到 Android Studio Flamingo 版本,而升级到 Flamingo 的话,默认自带的 Java 版本就会变成 JDK 17 ····· 所以,这就是你需要适配 AGP8 的主要原因之一。

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

Flamingo 兼容

首先,如下图所示,使用 Flamingo 不一定就要用 AGP 8,它的支持范围是 3.2- 8.0 ,但是,因为 Flamingo 默认自带的 Java 版本是 JDK 17 ,所以默认情况下你最低需要 AGP 7

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

为什么 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

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

当然,这里写了所需最低版本,所以你也可以用 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 版本。

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

最后,Gradle 版本还和 Kotlin 版本有关系,根据你使用的 Gradle 版本也需要配置对应的 kotlin-gradle-plugin 版本。

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

所以这里可以简单先总结一下:

  • 要使用 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 去打开。

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

如今的 AGP Upgrade Assistant 已然不是曾经的傻瓜式工具,它已经长大了。

如下图所示,如今的 AGP Upgrade Assistant 已经相当成熟, AS 会根据你当前的 AGP 版本,为你罗列出可以升级的 AGP 版本进行选择,同时你可以根据需要勾选迁移的选项,然后 Assistant 会根据你的选择自动调整你当前配置,这对于一些模块较多的项目在迁移时可以节省很多时间。

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

DSL 支持 namespace

说到 AGP8 适配,首先必提的就是 namespace 的适配需求,升级到 AGP 8 之后,在 Gradle Sync 的时候你可能会到类似的错误提示 :Namespace not specified ,这是因为 AGP 开始强制要求 namespace 配置

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

其实 AGP 7 开始就是有 namespace 配置,而 AGP 8 开始强制要求。

谷歌这次是希望通过 namespace 来让 package 属性得到释放,特别对于 Module 结构来说, namespace 更贴合认知逻辑,而不会像 package 一样还“夹带”了 applicationId 的属性。

namespace 也和后续的 R id 有关联。

如下图所示是需要调整的逻辑,主要就是移除了 Manifest 文件下的 package 属性 ,然后增加了 build.gradle 文件下的 namespace 配置,这一步推荐使用 AGP Upgrade Assistant 自动迁移,特别是对于 Module 比较多的项目,可以解放大量重复劳动

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

默认参数调整

如下图所示,AGP 8 里一些默认配置参数进行了调整,基本上这部分也是导致项目升级 AGP 8 跑不起来的「元凶」之一。

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

当然,如果你是使用 AGP Upgrade Assistant 进行升级迁移的话,一般情况下 Assistant 会根据你的项目情况自动进行适配,如下图就是 Assistant 在升级迁移时在 gradle,properties 下自动新增的部分。

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

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 声明而已,官方的自动化脚步处理还是挺方便的。

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

处理后也就是从 R 变成了 xxxxxx.xxxx.xxx.R 的效果:

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

nonFinalResIds

升级到 AGP8 ,你可能会看到一个错误: Resource IDs will be non-final ,这个问题主要出现在使用 switch 下的 R.id 场面,这个问题如果是没了解过,可能第一眼看到会觉得蒙圈,为什么不能用 R.id 了?

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

解决问题的最简单方式就是使用配置 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 中删除该类。

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

当然,如果你的项目里 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 APIInstrumentation API 来缩短构建时间 ,在此之前,我们一般通过 Transform API 在编译后的 class 文件转换为 dex 文件之前一些自定义打桩处理,而 AGP 8 开始,为了提高构建性能,使用 Transform API 很难与 Gradle 的其它特性结合,所以本次正式移除 Transform API ,这是一些第三方插件需要适配的地方。

另外,在做 Maven 发布的时候,需要添加对应的 singleVariant 来支持 publications 的兼容,虽然这不是 AGP 8 才开始的,但是也算是需要适配的点之一。

Android 更新后跑不起来?快来适配 AGP8 和 Flamingo/JDK 17

最后

AGP 8 和 Flamingo 需要兼容的问题大致就这样,可以看到 Android Studio 和 Gradle/Kotlin 关系捆绑得越来越紧密,如果不了解它们的依赖关系,处理器兼容就会迷失方向。

另外 AGP 现在的每个大版本变动也很大,比如前面没有特别介绍的 aidlrenderscript 配置位,下个大版本应该就会被移除了,只能说 Gradle 真的就是为了「折腾」而生。

如果你还有什么问题,欢迎评价交流。