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

文章目录

  • 前言
  • 开发环境
  • 问题描述
  • 问题分析
  • 解决方案
  • 最后


前言

在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

Flutter问题记录 - Unable to find bundled Java version(续)_第1张图片

从上篇文章的问题分析可以知道,问题出在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

Flutter问题记录 - Unable to find bundled Java version(续)_第2张图片

可以发现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中的解决方案。

最后

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

你可能感兴趣的:(问题记录,android,studio,flutter,android)