Flutter问题记录 - Unable to find bundled Java version(续)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

文章目录


前言

Flutter问题记录 - Unable to find bundled Java version文章中主要对Unable to find bundled Java version报错进行了分析虽然从最终结果上看Android端构建运行失败和出现这个报错的原因应该是一致的但是没有进行原因分析。这里做一些简单分析作为上篇文章的补充。

开发环境

  • 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

问题分析

当我们在Android Studio中点击运行Flutter项目到Android设备时控制台会输出

Launching xxx.dart on xxx in debug mode...
Running Gradle task 'assembleDebug'...
...

当然如果项目没执行过pub get还会有这个输出

Running "flutter pub get" in xxx...

对于Launching xxx.dart on xxx in debug mode...输出和要分析的问题没有什么关系不过如果你对整个运行流程感兴趣的话可以在Flutter框架项目下的packages/flutter_tools/lib/src/resident_runner.dart文件中找到这个输出的相关代码

final String modeName = coldRunner.debuggingOptions.buildInfo.friendlyModeName;
final bool prebuiltMode = coldRunner.applicationBinary != null;
globals.printStatus(
  'Launching ${getDisplayPath(coldRunner.mainPath, globals.fs)} '
  'on ${device!.name} in $modeName mode...',
);

对于Running Gradle task 'assembleDebug'...输出就是这次问题分析的关键了在Flutter框架项目下搜索关键词Running Gradle task

screenshot1

上篇文章的问题分析可以知道问题出在Android Studio移除了jre目录进而导致javaPath的拼接出现了问题。那现在这问题会不会是因为运行Gradle task时也用到了错误的javaPath呢继续在gradle.dart文件中搜索javaPath

gradle.dart文件中buildGradleApp方法的部分代码

try {
  exitCode = await _processUtils.stream(
    command,
    workingDirectory: project.android.hostAppGradleRoot.path,
    allowReentrantFlutter: true,
    environment: <String, String>{
      if (javaPath != null)
        'JAVA_HOME': javaPath!,
    },
    mapFunction: consumeLog,
  );
} on ProcessException catch (exception) {
  consumeLog(exception.toString());
  // Rethrow the exception if the error isn't handled by any of the
  // `localGradleErrors`.
  if (detectedGradleError == null) {
    rethrow;
  }
} finally {
  status.stop();
}

可以看到确实用到了javaPath那这个和android_studio.dart文件里面的javaPath有什么关联吗选中javaPath跳转定义的地方发现来到了android_studio.dart文件是一个顶级方法

String? get javaPath => globals.androidStudio?.javaPath;

Dart的顶级方法意味着只要导入android_studio.dart文件就可以直接调用javaPath方法。从方法定义中的javaPath继续跳转来到了AndroidStudio类里面。

AndroidStudio类部分代码

class AndroidStudio implements Comparable<AndroidStudio> {
  AndroidStudio(
    this.directory, {
    Version? version,
    this.configured,
    this.studioAppName = 'AndroidStudio',
    this.presetPluginsPath,
  }) : version = version ?? Version.unknown {
    _init(version: version);
  }
  
  String? _javaPath;
  bool _isValid = false;
  final List<String> _validationMessages = <String>[];

  String? get javaPath => _javaPath;

  void _init({Version? version}) {
    _isValid = false;
    _validationMessages.clear();

    if (configured != null) {
      _validationMessages.add('android-studio-dir = $configured');
    }

    if (!globals.fs.isDirectorySync(directory)) {
      _validationMessages.add('Android Studio not found at $directory');
      return;
    }

    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 {
      RunResult? result;
      try {
        result = globals.processUtils.runSync(<String>[javaExecutable, '-version']);
      } on ProcessException catch (e) {
        _validationMessages.add('Failed to run Java: $e');
      }
      if (result != null && result.exitCode == 0) {
        final List<String> versionLines = result.stderr.split('\n');
        final String javaVersion = versionLines.length >= 2 ? versionLines[1] : versionLines[0];
        _validationMessages.add('Java version $javaVersion');
        _javaPath = javaPath;
        _isValid = true;
      } else {
        _validationMessages.add('Unable to determine bundled Java version.');
      }
    }
  }
}

继续在类里面搜索_javaPath来到了AndroidStudio类的初始化方法_init

screenshot2

可以发现Android端构建运行和flutter doctor命令执行一样也用到了AndroidStudio类里面拼接的javaPath。当Android Studio移除jre目录后初始化androidStudio对象时拼接的javaPath路径有问题导致没有给_javaPath赋值从而导致Android端构建运行时获取的javaPathnull。由此可以验证Android端构建运行失败的原因和出现Unable to find bundled Java version报错的原因是一致的。

解决方案

请看这篇文章Flutter问题记录 - Unable to find bundled Java version中的解决方案。

最后

如果这篇文章对你有所帮助请不要吝啬你的点赞👍加星🌟谢谢~

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Java