有个紧急问题需要修复,本以为很快就能解决继续休假,没想到项目打开运行后Android端跑不起来了,iOS端正常运行,这就有点莫名其妙,明明放假前还是没问题的,难道我拉取的最新代码有问题?不会吧,谁放假还敲代码啊?🤔️看了下最新的提交记录,还是放假前我提交的,那就肯定不是项目的问题。
- Android Studio: 2022.1.1
- Flutter: 3.3.10
Android端构建运行失败,报错信息如下:
Execution failed for task ':app:processDebugMainManifest'.> Unable to make field private final java.lang.String java.io.File.path accessible: module java.base does not "opens java.io" to unnamed module
2023/08/14更新:当前问题已被修复,如果你还遇到以上报错,可以参考这篇文章Android问题记录 - Unable to make field private final java.lang.String java.io.File.path accessible(持续更新)。当然,如果你是Flutter开发者,当前文章也值得一读。
先网上搜一搜,大部分都是说JDK版本有问题,提到JDK版本我想到放假最后一天升级了Android Studio版本,从2021.3.1
升级到2022.1.1
,这应该算大版本更新,难道是这个升级导致JDK版本出问题了。尝试设置项目的JDK版本,折腾一番无果。
既然是Flutter项目,那可以尝试用Flutter命令检查Android Studio正不正常:
flutter doctor
执行输出:
[✓] Flutter (Channel stable, 3.3.10, on macOS 13.0.1 22A400 darwin-x64, locale zh-Hans-CN)[!] Android toolchain - develop for Android devices (Android SDK version 33.0.1) ✗ Android license status unknown. Run `flutter doctor --android-licenses` to accept the SDK licenses. See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.[✓] Xcode - develop for iOS and macOS (Xcode 14.2)[✓] Chrome - develop for the web[!] Android Studio (version 2022.1) ✗ Unable to find bundled Java version.[✓] IntelliJ IDEA Community Edition (version 2022.3.1)[✓] VS Code (version 1.74.2)[✓] Connected device (3 available)[✓] HTTP Host Availability
原来真有问题,还不止一个,那就逐个解决。
- Android license status unknown
这个问题的解决办法Flutter已经给出了,执行下方命令即可:
flutter doctor --android-licenses
执行输出:
Error: A JNI error has occurred, please check your installation and try againException in thread "main" java.lang.UnsupportedClassVersionError: com/android/prefs/AndroidLocationsProvider has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0at java.lang.ClassLoader.defineClass1(Native Method)at java.lang.ClassLoader.defineClass(ClassLoader.java:756)at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)at java.net.URLClassLoader.access$100(URLClassLoader.java:74)at java.net.URLClassLoader$1.run(URLClassLoader.java:369)at java.net.URLClassLoader$1.run(URLClassLoader.java:363)at java.security.AccessController.doPrivileged(Native Method)at java.net.URLClassLoader.findClass(URLClassLoader.java:362)at java.lang.ClassLoader.loadClass(ClassLoader.java:418)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)at java.lang.ClassLoader.loadClass(ClassLoader.java:351)at java.lang.Class.getDeclaredMethods0(Native Method)at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)at java.lang.Class.privateGetMethodRecursive(Class.java:3048)at java.lang.Class.getMethod0(Class.java:3018)at java.lang.Class.getMethod(Class.java:1784)at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:650)at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:632)
好家伙,这命令执行竟然报错了,我记得老早以前执行过没报错,网上一搜又是JDK版本问题。奇了怪了,虽然我电脑上有装多个版本的JDK,但是Android Studio一直是用的自带的JRE。
2023/08/14更新:当前问题已被修复,如果你还遇到以上报错,那么可能是JDK版本太低导致的,可以参考本篇文章评论中的方法,尝试升级JDK版本解决。
- Unable to find bundled Java version
这个报错是说找不到捆绑的Java版本🤔️,难道新版的Android Studio移除了自带的JRE?这么一想好像已经找到问题的根源所在了。接下来就是验证这个想法。
首先把Flutter框架项目代码拉下来,搜索关键词Unable to find bundled Java version
:
关键代码(位于Flutter框架项目下的packages/flutter_tools/lib/src/android/android_studio.dart
文件):
final String javaPath = globals.platform.isMacOS ? version != null && version.major < 2020 ? globals.fs.path.join(directory, 'jre', 'jdk', 'Contents', 'Home') : globals.fs.path.join(directory, 'jre', 'Contents', 'Home') : globals.fs.path.join(directory, 'jre');final String javaExecutable = globals.fs.path.join(javaPath, 'bin', 'java');if (!globals.processManager.canRun(javaExecutable)) { _validationMessages.add('Unable to find bundled Java version.');} else {// 省略}
这段代码的作用就是拼接Java可执行程序的路径,并验证是否能执行。现在我们把涉及到路径的几个变量打印出来,打印很简单,这是Dart写的,直接用print
方法就可以了。
print('directory: $directory');print('javaPath: $javaPath');print('javaExecutable: $javaExecutable');
现在的问题是怎么执行到修改后的文件,当我们执行flutter doctor
命令时,会执行到packages/flutter_tools/bin/flutter_tools.dart
文件(后面会分析),然后再进一步解析命令执行。所以我们直接通过Dart命令执行flutter_tools.dart
文件是不是就可以了。
dart flutter_tools.dart doctor
切换到Flutter框架项目的packages/flutter_tools/bin
目录下执行输出:
flutter_tools.dart:1:1: Error: The specified language version is too high. The highest supported language version is 2.18.// Copyright 2014 The Flutter Authors. All rights reserved.^../lib/executable.dart:1:1: Error: The specified language version is too high. The highest supported language version is 2.18.// Copyright 2014 The Flutter Authors. All rights reserved.^../lib/runner.dart:1:1: Error: The specified language version is too high. The highest supported language version is 2.18.// Copyright 2014 The Flutter Authors. All rights reserved.^../lib/src/artifacts.dart:1:1: Error: The specified language version is too high. The highest supported language version is 2.18.// Copyright 2014 The Flutter Authors. All rights reserved.^../lib/src/base/context.dart:1:1: Error: The specified language version is too high. The highest supported language version is 2.18.// Copyright 2014 The Flutter Authors. All rights reserved.^../lib/src/base/io.dart:1:1: Error: The specified language version is too high. The highest supported language version is 2.18.// Copyright 2014 The Flutter Authors. All rights reserved.^../lib/src/base/io.dart:28:8: Error: Expected an identifier, but got ';'.Try inserting an identifier before ';'.library; ^../lib/src/base/logger.dart:1:1: Error: The specified language version is too high. The highest supported language version is 2.18.// Copyright 2014 The Flutter Authors. All rights reserved.^../lib/src/base/platform.dart:1:1: Error: The specified language version is too high. The highest supported language version is 2.18.// Copyright 2014 The Flutter Authors. All rights reserved.^../lib/src/base/template.dart:1:1: Error: The specified language version is too high. The highest supported language version is 2.18.// Copyright 2014 The Flutter Authors. All rights reserved.^
执行报错了,原因是Dart SDK版本低了,电脑上当前的Dart SDK版本是2.18,拉下来的Flutter框架项目代码要求更高的版本。这时候不用去下载最新的Dart SDK版本,Flutter框架项目是自带Dart SDK的,位于项目bin/cache/dart-sdk
路径下。
2023/01/26更新:以上说明有点问题,实际的Flutter框架项目默认是不带Dart SDK的,如果你没找到,请看补充说明1。
指定Dart可执行程序路径:
flutter框架项目路径/bin/cache/dart-sdk/bin/dart flutter_tools.dart doctor
或者用这个,这个最终也是用到了bin/cache/dart-sdk/bin/dart
:
flutter框架项目路径/bin/dart flutter_tools.dart doctor
执行输出(省略部分):
directory: /Applications/Android Studio.app/ContentsjavaPath: /Applications/Android Studio.app/Contents/jre/Contents/HomejavaExecutable: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
接下来检查/Applications/Android Studio.app/Contents
路径下文件,可以选择[访达] -> [顶部菜单栏的前往] -> [前往文件夹] -> [输入路径跳转]或[应用程序] -> [Android Studio.app] -> [右键显示包内容] -> [Contents]。
实锤了,新版本的Android Studio真的移除了JRE,jre
目录找不到,怪不得报错了,不过多了一个jbr
目录,找了个以前的Android Studio版本对比(旧版下载,不是很全):
搜了一下jbr
(JetBrains Runtime),原来IDEA老早就开始用了,是基于OpenJDK修改的东西。不知道为什么Android Studio从2022.1.1
版本才开始支持,去下载了两个预览版也是没有jre
目录了,说明后续应该都没了。
综上,问题的根源在于Android Studo移除了jre
目录。那如果我直接修改代码,将路径拼接过程中的jre
改为jbr
是不是就没问题了,实测可行,执行flutter框架项目路径/bin/cache/dart-sdk/bin/dart flutter_tools.dart doctor
命令一切正常。
如果你略过了前面的问题分析,请注意,以下所说的jbr
所在目录路径为:
- macOS系统:
/Applications/Android Studio.app/Contents
- Windows系统:Android Studio的安装目录
2023/01/30更新:实测以下三种解决方法在Flutter 3.7.0版本依旧适用。对于前两种方法,如果你尝试后未能解决,请先检查上方所说的目录中是否有jre
目录或者软链接。
这里提供三种解决方法(任选一种):
- 简单粗暴的方法
- 如果是macOS系统,在
jbr
同目录下创建一个jre
目录,然后将jbr
目录内的全部文件复制一份到jre
目录下即可。 - 如果是Windows系统,
jre
目录是存在的,不过里面几乎没东西,可以直接将jbr
目录内的全部文件复制一份到jre
目录下即可。
- 创建软链接的方法
- 如果是macOS系统,切换到
jbr
所在目录执行命令:
ln -s jbr jre
注意,如果是通过cd命令切换到jbr
所在目录,需要对路径中的空格进行转义或用单/双引号包裹路径,例如cd /Applications/Android\ Studio.app/Contents
。
- 如果是Windows系统,使用管理员身份打开终端(可以按
Win+X键
,然后选择Windows 终端(管理员)
),切换到jbr
所在目录执行命令:
mklink /D jre jbr
这里有几点要注意:
- 一定要管理员身份运行,不然权限不足会报错提示
你没有足够的权限执行此操作
- 如果打开终端默认用的是
PowerShell
(输入命令那一行最前面有PS
字符),需要输入cmd
切换到命令提示符,这是因为PowerShell
不支持mklink
命令 - 执行命令前需要删除已经存在的
jre
目录,不然会报错提示当文件已存在时,无法创建该文件
- 右键创建快捷方式实测是行不通的,这种方式创建的快捷方式其实是创建了一个新的文件,只不过这个文件属性里面包含了目标路径,查看这个文件大小,才1000字节。通过
mklink
命令方式创建的,文件大小和占用空间等属性和目标文件属性一致。
2023/02/05更新:通过以上两种方法解决后,Android Studio后续升级可能会遇到如下所示问题:
如果你当前的Flutter版本已经修复了该问题,点击Proceed
删除添加的jre
目录或者软链接即可。如果还未修复又想继续升级(点击Proceed
),请按之前的方法将被删除的jre
目录或者软链接添加回去。
- 修改Flutter框架代码的方法(不推荐,有点麻烦,感兴趣的可以看看)
前面问题分析中尝试修改代码是可行的,但是那是在Flutter框架项目下改的,现在我们要做的是对当前电脑上的Flutter SDK进行修改。首先找到Flutter SDK目录:
如果你见过Flutter框架项目的目录结构,你会发现一模一样,那是不是说,直接修改目录下的packages/flutter_tools/lib/src/android/android_studio.dart
文件就好了,将jre
改为jbr
,实测没变化。这难道还需要编译?是的,确实还要做一些处理。
从flutter doctor
命令的执行开始分析,首先找到flutter
可执行文件(位于Flutter SDK的bin
目录下),这个本质是一个shell脚本,可以用文本工具打开,有点长就贴一个脚本的关键部分:
source "$BIN_DIR/internal/shared.sh"shared::execute "$@"
在脚本的最后执行了shared::execute
(::
是命名约定,用于分隔库)函数,并将命令执行时的参数传递下去。找到shared.sh
文件(位于Flutter SDK的bin/internal
目录下)中的shared::execute
函数:
# This function is intended to be executed by entrypoints (e.g. `//bin/flutter`# and `//bin/dart`). PROG_NAME and BIN_DIR should already be set by those# entrypoints.function shared::execute() { export FLUTTER_ROOT="$(cd "${BIN_DIR}/.." ; pwd -P)" # If present, run the bootstrap script first BOOTSTRAP_PATH="$FLUTTER_ROOT/bin/internal/bootstrap.sh" if [ -f "$BOOTSTRAP_PATH" ]; then source "$BOOTSTRAP_PATH" fi FLUTTER_TOOLS_DIR="$FLUTTER_ROOT/packages/flutter_tools" SNAPSHOT_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.snapshot" STAMP_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.stamp" SCRIPT_PATH="$FLUTTER_TOOLS_DIR/bin/flutter_tools.dart" DART_SDK_PATH="$FLUTTER_ROOT/bin/cache/dart-sdk" DART="$DART_SDK_PATH/bin/dart" # If running over git-bash, overrides the default UNIX executables with win32 # executables case "$(uname -s)" in MINGW*) DART="$DART.exe" ;; esac # Test if running as superuser – but don't warn if running within Docker or CI. if [[ "$EUID" == "0" && ! -f /.dockerenv && "$CI" != "true" && "$BOT" != "true" && "$CONTINUOUS_INTEGRATION" != "true" ]]; then >&2 echo " Woah! You appear to be trying to run flutter as root." >&2 echo " We strongly recommend running the flutter tool without superuser privileges." >&2 echo " /" >&2 echo "📎" fi # Test if Git is available on the Host if ! hash git 2>/dev/null; then >&2 echo "Error: Unable to find git in your PATH." exit 1 fi # Test if the flutter directory is a git clone (otherwise git rev-parse HEAD # would fail) if [[ ! -e "$FLUTTER_ROOT/.git" ]]; then >&2 echo "Error: The Flutter directory is not a clone of the GitHub project." >&2 echo " The flutter tool requires Git in order to operate properly;" >&2 echo " to install Flutter, see the instructions at:" >&2 echo " https://flutter.dev/get-started" exit 1 fi upgrade_flutter 7< "$PROG_NAME" BIN_NAME="$(basename "$PROG_NAME")" case "$BIN_NAME" in flutter*) # FLUTTER_TOOL_ARGS aren't quoted below, because it is meant to be # considered as separate space-separated args. exec "$DART" --disable-dart-dev --packages="$FLUTTER_TOOLS_DIR/.dart_tool/package_config.json" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@" ;; dart*) exec "$DART" "$@" ;; *) >&2 echo "Error! Executable name $BIN_NAME not recognized!" exit 1 ;; esac}
函数有点长,直接看最后面就好。最后有个分支语句,根据BIN_NAME
的值走不同分支,把相关的变量打印出来看看:
echo "PROG_NAME: $PROG_NAME"echo "BIN_NAME: $BIN_NAME"
执行flutter doctor
输出(省略部分):
PROG_NAME: /usr/local/Caskroom/flutter/3.3.10/flutter/bin/flutterBIN_NAME: flutter
根据输出结果可以判断,走的是第一个分支,执行exec "$DART" --disable-dart-dev --packages="$FLUTTER_TOOLS_DIR/.dart_tool/package_config.json" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@"
。之所以会有这个分支判断,是因为Dart命令最终也会执行到这个函数,执行Dart相关命令输出(省略部分):
PROG_NAME: /usr/local/Caskroom/flutter/3.3.10/flutter/bin/dartBIN_NAME: dart
分析到这,好像也没用到SCRIPT_PATH
变量(flutter_tools.dart
的路径,请看上述脚本函数代码中的定义),前面问题分析中提到执行flutter doctor
命令时,会执行到packages/flutter_tools/bin/flutter_tools.dart
文件,这难道是假的?不能说是假的,只能说有点偏差。如果是在这直接执行packages/flutter_tools/bin/flutter_tools.dart
文件的,那前面一开始修改代码就可以生效了,原因在于这边是用Dart命令执行SNAPSHOT_PATH
所指向的快照文件(flutter_tools.snapshot
)去了。
flutter_tools.snapshot
是通过Dart命令生成的快照文件,那我们是不是也可以生成一个快照文件替换掉自带的?切换到Flutter SDK目录的packages/flutter_tools/bin
路径下执行命令:
dart --snapshot=flutter_tools.snapshot flutter_tools.dart
2023/01/26更新:如果生成快照文件报错,请看补充说明2。
然后将生成的flutter_tools.snapshot
文件复制到bin/cache
目录下,注意,最好先备份原先的flutter_tools.snapshot
文件。对比文件大小,发现相差很小,那应该稳了,执行flutter doctor
输出:
Doctor summary (to see all details, run flutter doctor -v):[✓] Flutter (Channel stable, 3.3.10, on macOS 13.0.1 22A400 darwin-x64, locale zh-Hans-CN)[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)[✓] Xcode - develop for iOS and macOS (Xcode 14.2)[✓] Chrome - develop for the web[✓] Android Studio (version 2022.1)[✓] IntelliJ IDEA Community Edition (version 2022.3.1)[✓] VS Code (version 1.74.2)[✓] Connected device (3 available)[✓] HTTP Host Availability• No issues found!
一切正常!🎉
2023/01/26更新:注意,修改Flutter SDK文件后,后续使用Flutter命令升级时可能会提示你是否要保留这些改动,一般来说,使用flutter upgrade --force
命令强制升级即可。
快写完了,才发现差点忘了一开始是因为什么原因写这篇文章的,按以上解决方案做,如果执行flutter doctor
命令没问题,实测Android端构建运行也恢复正常了,所以这其实是同一个问题导致的,如果感兴趣的话,可以看看补充分析Flutter问题记录 - Unable to find bundled Java version(续)。
如果在Flutter框架项目中没找到Dart SDK,需要先执行命令:
flutter框架项目路径/bin/flutter
执行后,Flutter会自动下载Dart SDK,下载完成后会构建flutter tool
,也就是生成flutter_tools.snapshot
快照文件。
由于我执行过Flutter命令,所以一开始没注意到项目中默认是不带Dart SDK的。
也许执行命令后你还会遇到这样的问题:
Error: The Flutter directory is not a clone of the GitHub project. The flutter tool requires Git in order to operate properly; to install Flutter, see the instructions at: https://flutter.dev/get-started
解决方法:使用Git工具拉取Flutter框架项目代码,不要直接下载。
如果生成flutter_tools.snapshot
快照文件失败,报错提示:
../lib/src/test/flutter_tester_device.dart:180:11: Warning: Operand of null-aware operation '!' has type 'Uri' which excludes null. - 'Uri' is from 'dart:core'. forwardingUri!, ^../lib/runner.dart:9:8: Error: Error when reading '../../../.pub-cache/hosted/pub.flutter-io.cn/args-2.3.1/lib/command_runner.dart': No such file or directoryimport 'package:args/command_runner.dart'; ^../lib/src/runner/flutter_command.dart:6:8: Error: Error when reading '../../../.pub-cache/hosted/pub.flutter-io.cn/args-2.3.1/lib/command_runner.dart': No such file or directoryimport 'package:args/command_runner.dart'; ^../lib/runner.dart:10:8: Error: Error when reading '../../../.pub-cache/hosted/pub.flutter-io.cn/intl-0.17.0/lib/intl.dart': No such file or directoryimport 'package:intl/intl.dart' as intl; ^../lib/runner.dart:11:8: Error: Error when reading '../../../.pub-cache/hosted/pub.flutter-io.cn/intl-0.17.0/lib/intl_standalone.dart': No such file or directoryimport 'package:intl/intl_standalone.dart' as intl_standalone; ^../lib/src/runner/flutter_command_runner.dart:6:8: Error: Error when reading '../../../.pub-cache/hosted/pub.flutter-io.cn/args-2.3.1/lib/command_runner.dart': No such file or directoryimport 'package:args/command_runner.dart'; ^../lib/src/artifacts.dart:5:8: Error: Error when reading '../../../.pub-cache/hosted/pub.flutter-io.cn/file-6.1.4/lib/memory.dart': No such file or directoryimport 'package:file/memory.dart'; ^../lib/src/cache.dart:8:8: Error: Error when reading '../../../.pub-cache/hosted/pub.flutter-io.cn/file-6.1.4/lib/memory.dart': No such file or directoryimport 'package:file/memory.dart'; ^../lib/src/artifacts.dart:6:8: Error: Error when reading '../../../.pub-cache/hosted/pub.flutter-io.cn/process-4.2.4/lib/process.dart': No such file or directoryimport 'package:process/process.dart'; ^../lib/src/cache.dart:10:8: Error: Error when reading '../../../.pub-cache/hosted/pub.flutter-io.cn/process-4.2.4/lib/process.dart': No such file or directoryimport 'package:process/process.dart'; ^../lib/src/commands/analyze.dart:6:8: Error: Error when reading '../../../.pub-cache/hosted/pub.flutter-io.cn/process-4.2.4/lib/process.dart': No such file or directoryimport 'package:process/process.dart'; ^
执行命令获取flutter_tools
所需要的依赖包即可解决:
flutter update-packages
写完这篇文章,想着不知道有没有人提issue,要是没人提,我去提一个。没想到,老早就有人提了issue,应该是用Android Studio预览版的人提的,最近也还有人不断在重复提。
如果这篇文章对你有所帮助,点赞👍加星🌟支持一下吧,谢谢~
本篇文章由@crasowas发布于CSDN。
来源地址:https://blog.csdn.net/crasowas/article/details/128756923