Android gradle 中为什么要添加 java8 兼容配置?
太长不看版
当你的 Android gradle plugin
版本低于 4.2时(后面简称为AGP)。Android Studio
(后简称AS) 默认使用 java7
作为语法检查。
当你的代码,或者你依赖的代码中存在 java8 种的语法,比如 lambda
。 并且你没有添加 java8 兼容配置。AS在语法分析,或者编译的时候,都会报错。
lambda expressions are not supported in -source 7
为了解决这个报错,可以通过三种方式解决。
- 代码中消除 java8 的lambda。(很难做到)
- 添加 java8 的兼容配置 (容易做到)
- 升级 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
。
有人回复可以通过如下方式解决
dependency_overrides:
shared_preferences_android: 2.1.0
shared_preferences_ios: 2.1.0
可以看出是写死了 flutter
依赖的版本号。
在 flutter
中 ^2.10.0
代表取 2.10.x 的最高版本。去掉 ^
,就是写死版本号。
继续看这个 issue
,后面有人发了另外一个解决方式
对应的 pr
[github.com/flutter/pac…]
对应的代码片段如下:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
确实是在 shared_preferences
的 build.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 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
得到以下信息
上图中的 major version: 51 表示这个文件是由 java7 编译的。
验证场景二: 保留 java_1.8 兼容性代码, 运行命令 javap -v MainActivity.java
得到以下信息
上图中 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
来编译项目的。
思考二: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…
发现 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.1
的 agp
版本
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
}
转载自:https://juejin.cn/post/7223278436893327421