Reland "Allow for gradle downloading missing SDK assets" (#28097) (#28355)
* Allow for gradle downloading missing SDK assets if SDK licenses are present.
* Improvements for windows testing
diff --git a/packages/flutter_tools/lib/src/android/android_sdk.dart b/packages/flutter_tools/lib/src/android/android_sdk.dart
index 0bb5823..73432f0 100644
--- a/packages/flutter_tools/lib/src/android/android_sdk.dart
+++ b/packages/flutter_tools/lib/src/android/android_sdk.dart
@@ -263,7 +263,7 @@
class AndroidSdk {
AndroidSdk(this.directory, [this.ndk]) {
- _init();
+ reinitialize();
}
static const String _javaHomeEnvironmentVariable = 'JAVA_HOME';
@@ -278,6 +278,23 @@
List<AndroidSdkVersion> _sdkVersions;
AndroidSdkVersion _latestVersion;
+ /// Whether the `platform-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();
+
+ /// Whether the `licenses` directory exists in the Android SDK.
+ ///
+ /// The existence of this folder normally indicates that the SDK licenses have
+ /// been accepted, e.g. via the sdkmanager, Android Studio, or by copying them
+ /// from another workstation such as in CI scenarios. If these files are valid
+ /// gradle or the sdkmanager will be able to download and use other parts of
+ /// the SDK on demand.
+ bool get licensesAvailable => fs.directory(fs.path.join(directory, 'licenses')).existsSync();
+
static AndroidSdk locateAndroidSdk() {
String findAndroidHomeDir() {
String androidHomeDir;
@@ -348,14 +365,14 @@
}
static bool validSdkDirectory(String dir) {
- return fs.isDirectorySync(fs.path.join(dir, 'platform-tools'));
+ return fs.isDirectorySync(fs.path.join(dir, 'licenses'));
}
List<AndroidSdkVersion> get sdkVersions => _sdkVersions;
AndroidSdkVersion get latestVersion => _latestVersion;
- String get adbPath => getPlatformToolsPath('adb');
+ String get adbPath => getPlatformToolsPath(platform.isWindows ? 'adb.exe' : 'adb');
String get emulatorPath => getEmulatorPath();
@@ -376,8 +393,8 @@
/// Validate the Android SDK. This returns an empty list if there are no
/// issues; otherwise, it returns a list of issues found.
List<String> validateSdkWellFormed() {
- if (!processManager.canRun(adbPath))
- return <String>['Android SDK file not found: $adbPath.'];
+ if (adbPath == null || !processManager.canRun(adbPath))
+ return <String>['Android SDK file not found: ${adbPath ?? 'adb'}.'];
if (sdkVersions.isEmpty || latestVersion == null) {
final StringBuffer msg = StringBuffer('No valid Android SDK platforms found in ${_platformsDir.path}.');
@@ -396,7 +413,10 @@
}
String getPlatformToolsPath(String binaryName) {
- return fs.path.join(directory, 'platform-tools', binaryName);
+ final String path = fs.path.join(directory, 'platform-tools', binaryName);
+ if (fs.file(path).existsSync())
+ return path;
+ return null;
}
String getEmulatorPath() {
@@ -420,7 +440,11 @@
return null;
}
- void _init() {
+ /// Sets up various paths used internally.
+ ///
+ /// This method should be called in a case where the tooling may have updated
+ /// SDK artifacts, such as after running a gradle build.
+ void reinitialize() {
List<Version> buildTools = <Version>[]; // 19.1.0, 22.0.1, ...
final Directory buildToolsDir = fs.directory(fs.path.join(directory, 'build-tools'));