[flutter_tools] support new SDK structure for sdkmanager (#51980) (#53194)
diff --git a/packages/flutter_tools/lib/src/android/android_sdk.dart b/packages/flutter_tools/lib/src/android/android_sdk.dart
index 6fbe3d3..09f8404 100644
--- a/packages/flutter_tools/lib/src/android/android_sdk.dart
+++ b/packages/flutter_tools/lib/src/android/android_sdk.dart
@@ -283,13 +283,15 @@
List<AndroidSdkVersion> _sdkVersions;
AndroidSdkVersion _latestVersion;
- /// Whether the `platform-tools` directory exists in the Android SDK.
+ /// Whether the `platform-tools` or `cmdline-tools` directory exists in the Android SDK.
///
/// It is possible to have an Android SDK folder that is missing this with
/// the expectation that it will be downloaded later, e.g. by gradle or the
/// sdkmanager. The [licensesAvailable] property should be used to determine
/// whether the licenses are at least possibly accepted.
- bool get platformToolsAvailable => fs.directory(fs.path.join(directory, 'platform-tools')).existsSync();
+ bool get platformToolsAvailable =>
+ fs.directory(fs.path.join(directory, 'cmdline-tools')).existsSync() ||
+ fs.directory(fs.path.join(directory, 'platform-tools')).existsSync();
/// Whether the `licenses` directory exists in the Android SDK.
///
@@ -531,8 +533,17 @@
_latestVersion = _sdkVersions.isEmpty ? null : _sdkVersions.last;
}
- /// Returns the filesystem path of the Android SDK manager tool or null if not found.
+ /// Returns the filesystem path of the Android SDK manager tool.
+ ///
+ /// The sdkmanager was previously in the tools directory but this component
+ /// was marked as obsolete in 3.6.
String get sdkManagerPath {
+ final File cmdlineTool = fs.file(
+ fs.path.join(directory, 'cmdline-tools', 'latest', 'bin', 'sdkmanager')
+ );
+ if (cmdlineTool.existsSync()) {
+ return cmdlineTool.path;
+ }
return fs.path.join(directory, 'tools', 'bin', 'sdkmanager');
}
diff --git a/packages/flutter_tools/lib/src/android/android_workflow.dart b/packages/flutter_tools/lib/src/android/android_workflow.dart
index 543067b..3d415b4 100644
--- a/packages/flutter_tools/lib/src/android/android_workflow.dart
+++ b/packages/flutter_tools/lib/src/android/android_workflow.dart
@@ -311,12 +311,6 @@
throwToolExit(userMessages.androidMissingSdkManager(androidSdk.sdkManagerPath));
}
- final Version sdkManagerVersion = Version.parse(androidSdk.sdkManagerVersion);
- if (sdkManagerVersion == null || sdkManagerVersion.major < 26) {
- // SDK manager is found, but needs to be updated.
- throwToolExit(userMessages.androidSdkManagerOutdated(androidSdk.sdkManagerPath));
- }
-
try {
final Process process = await processUtils.start(
<String>[androidSdk.sdkManagerPath, '--licenses'],
diff --git a/packages/flutter_tools/test/general.shard/android/android_sdk_test.dart b/packages/flutter_tools/test/general.shard/android/android_sdk_test.dart
index 684e57d..98e4154 100644
--- a/packages/flutter_tools/test/general.shard/android/android_sdk_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/android_sdk_test.dart
@@ -8,6 +8,7 @@
import 'package:flutter_tools/src/base/io.dart' show ProcessResult;
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/config.dart';
+import 'package:flutter_tools/src/globals.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
@@ -60,11 +61,27 @@
ProcessManager: () => FakeProcessManager.any(),
});
- testUsingContext('returns sdkmanager path', () {
+ testUsingContext('returns sdkmanager path under cmdline tools', () {
sdkDir = MockAndroidSdk.createSdkDirectory();
Config.instance.setValue('android-sdk', sdkDir.path);
final AndroidSdk sdk = AndroidSdk.locateAndroidSdk();
+ fs.file(
+ fs.path.join(sdk.directory, 'cmdline-tools', 'latest', 'bin', 'sdkmanager')
+ ).createSync(recursive: true);
+
+ expect(sdk.sdkManagerPath, fs.path.join(sdk.directory, 'cmdline-tools', 'latest', 'bin', 'sdkmanager'));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ ProcessManager: () => FakeProcessManager.any(),
+ });
+
+ testUsingContext('returns sdkmanager path under tools if cmdline doesnt exist', () {
+ sdkDir = MockAndroidSdk.createSdkDirectory();
+ config.setValue('android-sdk', sdkDir.path);
+
+ final AndroidSdk sdk = AndroidSdk.locateAndroidSdk();
+
expect(sdk.sdkManagerPath, fs.path.join(sdk.directory, 'tools', 'bin', 'sdkmanager'));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
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 5807ef9..a3b374b 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
@@ -154,32 +154,6 @@
Stdio: () => stdio,
}));
- testUsingContext('runLicenseManager errors for version < 26', () async {
- when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
- when(sdk.sdkManagerVersion).thenReturn('25.0.0');
-
- expect(AndroidLicenseValidator.runLicenseManager(), throwsToolExit(message: 'To update, run'));
- }, overrides: Map<Type, Generator>.unmodifiable(<Type, Generator>{
- AndroidSdk: () => sdk,
- FileSystem: () => fs,
- ProcessManager: () => processManager,
- Platform: () => FakePlatform()..environment = <String, String>{'HOME': '/home/me'},
- Stdio: () => stdio,
- }));
-
- testUsingContext('runLicenseManager errors correctly for null version', () async {
- when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
- when(sdk.sdkManagerVersion).thenReturn(null);
-
- expect(AndroidLicenseValidator.runLicenseManager(), throwsToolExit(message: 'To update, run'));
- }, overrides: Map<Type, Generator>.unmodifiable(<Type, Generator>{
- AndroidSdk: () => sdk,
- FileSystem: () => fs,
- ProcessManager: () => processManager,
- Platform: () => FakePlatform()..environment = <String, String>{'HOME': '/home/me'},
- Stdio: () => stdio,
- }));
-
testUsingContext('runLicenseManager errors when sdkmanager is not found', () async {
when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
processManager.canRunSucceeds = false;