From f4879f03ec028323ca2dfc4543b59faad204d39b Mon Sep 17 00:00:00 2001 From: Reid Baker <1063596+reidbaker@users.noreply.github.com> Date: Fri, 26 Sep 2025 20:37:47 +0000 Subject: [PATCH] Add warn java evaluation to android_workflow (#176097) Related to #176027 Needs to land after https://github.com/flutter/flutter/pull/176094 - **Add java warn and error to android workflow** ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../main/kotlin/DependencyVersionChecker.kt | 1 + .../lib/src/android/android_workflow.dart | 10 ++++- .../lib/src/android/gradle_utils.dart | 4 +- .../lib/src/base/user_messages.dart | 3 +- .../android/android_workflow_test.dart | 43 +++++++++++++++++++ 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/packages/flutter_tools/gradle/src/main/kotlin/DependencyVersionChecker.kt b/packages/flutter_tools/gradle/src/main/kotlin/DependencyVersionChecker.kt index 7179fa26be7..2227f7c1fc0 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/DependencyVersionChecker.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/DependencyVersionChecker.kt @@ -94,6 +94,7 @@ object DependencyVersionChecker { @VisibleForTesting internal val errorGradleVersion: Version = Version(8, 3, 0) + // Java error and warn should align with packages/flutter_tools/lib/src/android/gradle_utils.dart. @VisibleForTesting internal val warnJavaVersion: JavaVersion = JavaVersion.VERSION_17 @VisibleForTesting internal val errorJavaVersion: JavaVersion = JavaVersion.VERSION_11 diff --git a/packages/flutter_tools/lib/src/android/android_workflow.dart b/packages/flutter_tools/lib/src/android/android_workflow.dart index 159a5852a28..3b9ca1b0e7f 100644 --- a/packages/flutter_tools/lib/src/android/android_workflow.dart +++ b/packages/flutter_tools/lib/src/android/android_workflow.dart @@ -131,7 +131,7 @@ class AndroidValidator extends DoctorValidator { String? _task; /// Returns false if we cannot determine the Java version or if the version - /// is older that the minimum allowed version of 1.8. + /// is older that the minimum allowed version. Future _checkJavaVersion(List messages) async { _task = 'Checking Java status'; try { @@ -160,12 +160,18 @@ class AndroidValidator extends DoctorValidator { return false; } // Should this be modified to be evaluated based on gradle version used? - if (javaVersion < gradle_utils.minJavaMinVersionAndroid) { + if (javaVersion < gradle_utils.errorJavaMinVersionAndroid) { messages.add( ValidationMessage.error(_userMessages.androidJavaMinimumVersion(javaVersion.toString())), ); return false; } + if (javaVersion < gradle_utils.warnJavaMinVersionAndroid) { + messages.add( + ValidationMessage.hint(_userMessages.androidJavaMinimumVersion(javaVersion.toString())), + ); + return true; + } messages.add(ValidationMessage(_userMessages.androidJavaVersion(javaVersion.toString()))); return true; } finally { diff --git a/packages/flutter_tools/lib/src/android/gradle_utils.dart b/packages/flutter_tools/lib/src/android/gradle_utils.dart index b8055a38902..4e158b4d534 100644 --- a/packages/flutter_tools/lib/src/android/gradle_utils.dart +++ b/packages/flutter_tools/lib/src/android/gradle_utils.dart @@ -58,7 +58,9 @@ const minSdkVersion = '$minSdkVersionInt'; const targetSdkVersion = '36'; const ndkVersion = '27.0.12077973'; final minBuildToolsVersion = Version(28, 0, 3); -final minJavaMinVersionAndroid = Version(11, 0, 0); +// Align with packages/flutter_tools/gradle/src/main/kotlin/DependencyVersionChecker.kt. +final errorJavaMinVersionAndroid = Version(11, 0, 0); +final warnJavaMinVersionAndroid = Version(17, 0, 0); // Update these when new major versions of Java are supported by new Gradle // versions that we support. diff --git a/packages/flutter_tools/lib/src/base/user_messages.dart b/packages/flutter_tools/lib/src/base/user_messages.dart index a9e6463fe6b..3e2fc5fadca 100644 --- a/packages/flutter_tools/lib/src/base/user_messages.dart +++ b/packages/flutter_tools/lib/src/base/user_messages.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import '../android/gradle_utils.dart' as gradle_utils; import 'platform.dart'; /// Class containing some message strings that can be produced by Flutter tools. @@ -84,7 +85,7 @@ class UserMessages { String get androidUnknownJavaVersion => 'Could not determine java version'; String androidJavaVersion(String javaVersion) => 'Java version $javaVersion'; String androidJavaMinimumVersion(String javaVersion) => - 'Java version $javaVersion is older than the minimum recommended version of 1.8'; + 'Java version $javaVersion is older than the minimum recommended version of ${gradle_utils.warnJavaMinVersionAndroid}'; String androidSdkLicenseOnly(String envKey) => 'Android SDK contains licenses only.\n' 'Your first build of an Android application will take longer than usual, ' diff --git a/packages/flutter_tools/test/general.shard/android/android_workflow_test.dart b/packages/flutter_tools/test/general.shard/android/android_workflow_test.dart index 54326563e0a..b0cd70e13e9 100644 --- a/packages/flutter_tools/test/general.shard/android/android_workflow_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_workflow_test.dart @@ -636,6 +636,49 @@ Review licenses that have not been accepted (y/N)? ); }); + testUsingContext('detects minimum recommended java version', () async { + // Test with older version of JDK + final Platform platform = FakePlatform() + ..environment = { + 'HOME': '/home/me', + Java.javaHomeEnvironmentVariable: 'home/java', + 'PATH': '', + }; + final sdkVersion = FakeAndroidSdkVersion() + ..sdkLevel = gradle_utils.compileSdkVersionInt + ..buildToolsVersion = gradle_utils.minBuildToolsVersion; + + // Mock a pass through scenario to reach _checkJavaVersion() + sdk + ..licensesAvailable = true + ..platformToolsAvailable = true + ..cmdlineToolsAvailable = true + ..directory = fileSystem.directory('/foo/bar') + ..sdkManagerPath = '/foo/bar/sdkmanager' + ..emulatorPath = 'path/to/emulator'; + sdk.latestVersion = sdkVersion; + + const javaVersionText = 'openjdk version "16.0.1"'; + final String errorMessage = UserMessages().androidJavaMinimumVersion(javaVersionText); + + final ValidationResult validationResult = await AndroidValidator( + java: FakeJava(version: const Version.withText(16, 0, 1, javaVersionText)), + androidSdk: sdk, + logger: logger, + platform: platform, + userMessages: UserMessages(), + processManager: processManager, + ).validate(); + expect(validationResult.type, ValidationType.success); + expect(validationResult.messages.last.message, errorMessage); + expect( + validationResult.messages.any( + (ValidationMessage message) => message.message.contains('Unable to locate Android SDK'), + ), + false, + ); + }); + testWithoutContext('Mentions `flutter config --android-sdk if user has no AndroidSdk`', () async { final ValidationResult validationResult = await AndroidValidator( java: FakeJava(),