likes
comments
collection
share

Android gradle 中为什么要添加 java8 兼容配置?

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

太长不看版

当你的 Android gradle plugin 版本低于 4.2时(后面简称为AGP)。Android Studio(后简称AS) 默认使用 java7 作为语法检查。

当你的代码,或者你依赖的代码中存在 java8 种的语法,比如 lambda。 并且你没有添加 java8 兼容配置。AS在语法分析,或者编译的时候,都会报错。

lambda expressions are not supported in -source 7 

为了解决这个报错,可以通过三种方式解决。

  1. 代码中消除 java8 的lambda。(很难做到)
  2. 添加 java8 的兼容配置 (容易做到)
  3. 升级 AGP 到 4.2 (中等难度)

所以,为了解决这个错误,选择方式 2 是较为容易的。

遇到了问题

项目是一个混合 Flutter 的项目,使用到了 flutter shared_preferences。 在4.15日打包失败,错误提示为:

.../flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_android-2.1.1/android/src/main/java/io/flutter/plugins/sharedpreferences/Messages.java:84: error: static interface methods are not supported in -source 7  
static [@nonnull](https://github.com/nonnull) MessageCodec getCodec() {  
^  
(use -source 8 or higher to enable static interface methods)  
.../flutter/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_android-2.1.1/android/src/main/java/io/flutter/plugins/sharedpreferences/Messages.java:103: error: lambda expressions are not supported in -source 7  
(message, reply) -> {  
^  
(use -source 8 or higher to enable lambda expressions)  
2 errors

检查 shared_preferences 依赖为 ^2.10.0。 最近一周没有改过这个依赖,并且最近打包都是正常的。

在搜索引擎中搜索 -source 8 or higher to enable lambda expressions 提示应该在项目中添加

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

但是主项目已经添加过这个代码块了,难道要改 shared_preferences?

查找解决方案

查找 flutter shared_preferences github 。发现有这个 issue

[(github.com/flutter/flu…)]

有人回复可以通过如下方式解决

Android gradle 中为什么要添加 java8 兼容配置?

dependency_overrides:
  shared_preferences_android: 2.1.0
  shared_preferences_ios: 2.1.0

可以看出是写死了 flutter 依赖的版本号。

flutter^2.10.0代表取 2.10.x 的最高版本。去掉 ^,就是写死版本号。

继续看这个 issue ,后面有人发了另外一个解决方式

Android gradle 中为什么要添加 java8 兼容配置?

对应的 pr[github.com/flutter/pac…]

对应的代码片段如下:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8 
    targetCompatibility JavaVersion.VERSION_1_8
 }

确实是在 shared_preferencesbuild.gradle 中添加的,也解决了问题,不再报错。

思考: 为什么可以这样解决

问问 chatgpt 下面这段代码是什么意思?

: Android 中下面这段代码是什么意思

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8 
    targetCompatibility JavaVersion.VERSION_1_8
}

:

这段代码是在 Android build.gradle 文件中的配置选项,它指定了 Java 代码编译时所使用的源码和目标代码兼容性版本都为 Java 8。

- `sourceCompatibility JavaVersion.VERSION_1_8` 表示源码兼容性版本为 Java 8。
- `targetCompatibility JavaVersion.VERSION_1_8` 表示目标代码兼容性版本为 Java 8。

这意味着你可以在你的代码中使用 Java 8 的新语言特性和 API,并且编译后的 APK 可以在支持 Java 8 的设备上运行。

反问自己:理解了吗?

自问自答:没有。

尝试:如果在我的项目里去掉 sourceCompatibility JavaVersion.VERSION_1_8 会怎么样?

IDE 直接摆烂

Android gradle 中为什么要添加 java8 兼容配置?

猜测: Android Studio 默认使用 Java 7 用于代码检查,以及编译吗?

验证猜测

前置准备

1: 需要用的命令

javap -v file

通过这个命令,可以得到 .class 文件对应的java编译版本

2: Android项目中编译出来的 .class 文件在哪里?

Android项目中,java文件的编译产物目录为:

app/build/intermediates/javac/debug/compileDebugJavaWithJavac

如果你发现这个目录下是空的,试试下面几个办法

  • 确定你的已经 rebuild 成功
  • 删除 build 目录,并且 rebuild 项目
  • 如果你没有 java 代码,都是 kotlin 代码,那么这个目录肯定是空的。写一个 java 类吧。
验证场景一: 删除 java_1.8 兼容性代码, 运行命令 javap -v MainActivity.java

得到以下信息

Android gradle 中为什么要添加 java8 兼容配置?

上图中的 major version: 51 表示这个文件是由 java7 编译的。

验证场景二: 保留 java_1.8 兼容性代码, 运行命令 javap -v MainActivity.java

得到以下信息

Android gradle 中为什么要添加 java8 兼容配置?

上图中 major version: 52 表示这个文件是由 java 8 编译的。

初步结论:Android Studio 默认用 java7 编译代码。

如果需要 java8 的语法,比如 lambda,需要额外加上

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8 
    targetCompatibility JavaVersion.VERSION_1_8
}

上面的结论是有误的,下面继续说为什么错误。

再思考:是谁决定了这个编译版本的?

思考一:项目怎么用 java7 来编译了?

Android Studio 中,JDK 的版本号已经是 java8 或者是 java11。 我绝对不会指定 java7来编译项目的。

Android gradle 中为什么要添加 java8 兼容配置?

思考二:sp的开发者有那么不专业吗?

shared_preferences_android 项目,提交 2.1.11版本的那位开发同学。 具体提交 commit [github.com/flutter/pac…]

他写这些代码的时候,IDE直接也报错了吧,还能提交吗?不可能这么不专业吧。

因此我猜测有其他工具,来确定项目使用什么版本的 java 来编译。

猜测一: 是 gradle 决定项目的java编译版本吗?

验证猜测:直接问 chatgpt

问:android gradle 会使用什么java版本来编译android项目?

答:

根据官方文档,Android Gradle插件默认使用Java 8版本来编译Android项目。然而,从Android Gradle插件3.0版本开始,还支持使用Java 7或更高版本来编译Android项目。

开发者可以在build.gradle文件中的android {}代码块中通过设置compileOptions {}来指定使用的Java版本。例如,设置为Java 7:


android {
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_7
    targetCompatibility JavaVersion.VERSION_1_7
  }
}

注意,要在项目中使用Java 8的新特性(例如Lambda表达式),需要在应用模块的build.gradle文件中添加以下代码来启用Java 8语言功能:

android {
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }

  // For Java 8 language support
  jackOptions {
    enabled true
  }
}


但是从Android Gradle插件3.0版本开始,官方已经弃用Jack编译器,建议使用Java 8语言功能时,使用D8或R8编译器。

chatgpt得到的答案为 Android Gradle Plugin ,简称 AGP,决定了Android项目的java编译版本。

那么 AGP 版本和 Java编译版本的关系是什么呢?

浏览了 AGP 发布的日志 developer.android.google.cn/build/relea…

Android gradle 中为什么要添加 java8 兼容配置?

发现 AGP 从 4.2 版本开始,默认使用 java8 来编译代码,并且 AS 以 java8 作为检查基准,就是图片中的 language level

可以得到结论: 当你的 AGP 版本高于或等于 4.2 ,你不需要添加

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }

也可以使用 java8 语法糖,编译器会默认使用 java8 来编译你的代码。

小结:项目的编译版本默认是 AGP 版本决定的。或者你可以添加兼容性代码来决定编译版本。

回答上面的猜疑二:

shared_preferences_android 项目,提交 2.1.11版本的那位开发同学。 具体提交 commit 他写这些代码的时候,IDE直接也报错了吧,还能提交吗?不可能这么不专业吧。

查看 shared_preferences_android 2.11.1agp 版本

github.com/flutter/pac…

Android gradle 中为什么要添加 java8 兼容配置?

AGP 7.2.2 默认使用 java8 来编译项目。 所以提交 shared_preferences_android lambda 代码的开发者,项目不会报错。

因此可以得到如下小结:项目中 AGP 版本为 4.1.2,默认使用 java7 编译项目, 第三方依赖的 AGP 即便设置到高版本,也会使用 主项目的低版本 AGP

如果第三方依赖要使用 java8 lambda,必须添加兼容配置。

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }