mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Allow for gradle downloading missing SDK assets (#28097)
* Allow for gradle downloading missing SDK assets if SDK licenses are present. * Fix license path for missing sdkmanager * Cirrus re-run... * Fix condition check * rename props, add docs, rename method * fix tests after param changes * Fix weird path for flutter run and add tests * remove print, fix tests
This commit is contained in:
parent
b316940051
commit
6f5e88a59f
@ -372,7 +372,7 @@ class AndroidDevice extends Device {
|
|||||||
if (buildInfo.targetPlatform == null && devicePlatform == TargetPlatform.android_arm64)
|
if (buildInfo.targetPlatform == null && devicePlatform == TargetPlatform.android_arm64)
|
||||||
buildInfo = buildInfo.withTargetPlatform(TargetPlatform.android_arm64);
|
buildInfo = buildInfo.withTargetPlatform(TargetPlatform.android_arm64);
|
||||||
|
|
||||||
if (!prebuiltApplication) {
|
if (!prebuiltApplication || androidSdk.licensesAvailable && androidSdk.latestVersion == null) {
|
||||||
printTrace('Building APK');
|
printTrace('Building APK');
|
||||||
final FlutterProject project = await FlutterProject.current();
|
final FlutterProject project = await FlutterProject.current();
|
||||||
await buildApk(
|
await buildApk(
|
||||||
|
@ -263,7 +263,7 @@ class AndroidNdk {
|
|||||||
|
|
||||||
class AndroidSdk {
|
class AndroidSdk {
|
||||||
AndroidSdk(this.directory, [this.ndk]) {
|
AndroidSdk(this.directory, [this.ndk]) {
|
||||||
_init();
|
reinitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const String _javaHomeEnvironmentVariable = 'JAVA_HOME';
|
static const String _javaHomeEnvironmentVariable = 'JAVA_HOME';
|
||||||
@ -278,6 +278,23 @@ class AndroidSdk {
|
|||||||
List<AndroidSdkVersion> _sdkVersions;
|
List<AndroidSdkVersion> _sdkVersions;
|
||||||
AndroidSdkVersion _latestVersion;
|
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() {
|
static AndroidSdk locateAndroidSdk() {
|
||||||
String findAndroidHomeDir() {
|
String findAndroidHomeDir() {
|
||||||
String androidHomeDir;
|
String androidHomeDir;
|
||||||
@ -348,7 +365,7 @@ class AndroidSdk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool validSdkDirectory(String dir) {
|
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;
|
List<AndroidSdkVersion> get sdkVersions => _sdkVersions;
|
||||||
@ -376,8 +393,8 @@ class AndroidSdk {
|
|||||||
/// Validate the Android SDK. This returns an empty list if there are no
|
/// Validate the Android SDK. This returns an empty list if there are no
|
||||||
/// issues; otherwise, it returns a list of issues found.
|
/// issues; otherwise, it returns a list of issues found.
|
||||||
List<String> validateSdkWellFormed() {
|
List<String> validateSdkWellFormed() {
|
||||||
if (!processManager.canRun(adbPath))
|
if (adbPath == null || !processManager.canRun(adbPath))
|
||||||
return <String>['Android SDK file not found: $adbPath.'];
|
return <String>['Android SDK file not found: ${adbPath ?? 'adb'}.'];
|
||||||
|
|
||||||
if (sdkVersions.isEmpty || latestVersion == null) {
|
if (sdkVersions.isEmpty || latestVersion == null) {
|
||||||
final StringBuffer msg = StringBuffer('No valid Android SDK platforms found in ${_platformsDir.path}.');
|
final StringBuffer msg = StringBuffer('No valid Android SDK platforms found in ${_platformsDir.path}.');
|
||||||
@ -396,7 +413,10 @@ class AndroidSdk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String getPlatformToolsPath(String binaryName) {
|
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() {
|
String getEmulatorPath() {
|
||||||
@ -420,7 +440,11 @@ class AndroidSdk {
|
|||||||
return null;
|
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, ...
|
List<Version> buildTools = <Version>[]; // 19.1.0, 22.0.1, ...
|
||||||
|
|
||||||
final Directory buildToolsDir = fs.directory(fs.path.join(directory, 'build-tools'));
|
final Directory buildToolsDir = fs.directory(fs.path.join(directory, 'build-tools'));
|
||||||
|
@ -105,6 +105,11 @@ class AndroidValidator extends DoctorValidator {
|
|||||||
return ValidationResult(ValidationType.missing, messages);
|
return ValidationResult(ValidationType.missing, messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (androidSdk.licensesAvailable && !androidSdk.platformToolsAvailable) {
|
||||||
|
messages.add(ValidationMessage.hint(userMessages.androidSdkLicenseOnly(kAndroidHome)));
|
||||||
|
return ValidationResult(ValidationType.partial, messages);
|
||||||
|
}
|
||||||
|
|
||||||
messages.add(ValidationMessage(userMessages.androidSdkLocation(androidSdk.directory)));
|
messages.add(ValidationMessage(userMessages.androidSdkLocation(androidSdk.directory)));
|
||||||
|
|
||||||
messages.add(ValidationMessage(androidSdk.ndk == null
|
messages.add(ValidationMessage(androidSdk.ndk == null
|
||||||
@ -249,7 +254,9 @@ class AndroidLicenseValidator extends DoctorValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ensureCanRunSdkManager();
|
if (!_canRunSdkManager()) {
|
||||||
|
return LicensesAccepted.unknown;
|
||||||
|
}
|
||||||
|
|
||||||
final Process process = await runCommand(
|
final Process process = await runCommand(
|
||||||
<String>[androidSdk.sdkManagerPath, '--licenses'],
|
<String>[androidSdk.sdkManagerPath, '--licenses'],
|
||||||
@ -279,7 +286,9 @@ class AndroidLicenseValidator extends DoctorValidator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ensureCanRunSdkManager();
|
if (!_canRunSdkManager()) {
|
||||||
|
throwToolExit(userMessages.androidMissingSdkManager(androidSdk.sdkManagerPath));
|
||||||
|
}
|
||||||
|
|
||||||
final Version sdkManagerVersion = Version.parse(androidSdk.sdkManagerVersion);
|
final Version sdkManagerVersion = Version.parse(androidSdk.sdkManagerVersion);
|
||||||
if (sdkManagerVersion == null || sdkManagerVersion.major < 26) {
|
if (sdkManagerVersion == null || sdkManagerVersion.major < 26) {
|
||||||
@ -306,10 +315,9 @@ class AndroidLicenseValidator extends DoctorValidator {
|
|||||||
return exitCode == 0;
|
return exitCode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _ensureCanRunSdkManager() {
|
static bool _canRunSdkManager() {
|
||||||
assert(androidSdk != null);
|
assert(androidSdk != null);
|
||||||
final String sdkManagerPath = androidSdk.sdkManagerPath;
|
final String sdkManagerPath = androidSdk.sdkManagerPath;
|
||||||
if (!processManager.canRun(sdkManagerPath))
|
return processManager.canRun(sdkManagerPath);
|
||||||
throwToolExit(userMessages.androidMissingSdkManager(sdkManagerPath));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import 'package:meta/meta.dart';
|
|||||||
|
|
||||||
import '../base/common.dart';
|
import '../base/common.dart';
|
||||||
import '../build_info.dart';
|
import '../build_info.dart';
|
||||||
import '../globals.dart';
|
|
||||||
import '../project.dart';
|
import '../project.dart';
|
||||||
|
|
||||||
import 'android_sdk.dart';
|
import 'android_sdk.dart';
|
||||||
@ -32,18 +31,11 @@ Future<void> buildApk({
|
|||||||
if (androidSdk == null)
|
if (androidSdk == null)
|
||||||
throwToolExit('No Android SDK found. Try setting the ANDROID_SDK_ROOT environment variable.');
|
throwToolExit('No Android SDK found. Try setting the ANDROID_SDK_ROOT environment variable.');
|
||||||
|
|
||||||
final List<String> validationResult = androidSdk.validateSdkWellFormed();
|
await buildGradleProject(
|
||||||
if (validationResult.isNotEmpty) {
|
|
||||||
for (String message in validationResult) {
|
|
||||||
printError(message, wrap: false);
|
|
||||||
}
|
|
||||||
throwToolExit('Try re-installing or updating your Android SDK.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return buildGradleProject(
|
|
||||||
project: project,
|
project: project,
|
||||||
buildInfo: buildInfo,
|
buildInfo: buildInfo,
|
||||||
target: target,
|
target: target,
|
||||||
isBuildingBundle: false
|
isBuildingBundle: false
|
||||||
);
|
);
|
||||||
|
androidSdk.reinitialize();
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,21 @@ Future<GradleProject> _gradleProject() async {
|
|||||||
return _cachedGradleProject;
|
return _cachedGradleProject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Runs `gradlew dependencies`, ensuring that dependencies are resolved and
|
||||||
|
/// potentially downloaded.
|
||||||
|
Future<void> checkGradleDependencies() async {
|
||||||
|
final Status progress = logger.startProgress('Ensuring gradle dependencies are up to date...', timeout: kSlowOperation);
|
||||||
|
final FlutterProject flutterProject = await FlutterProject.current();
|
||||||
|
final String gradle = await _ensureGradle(flutterProject);
|
||||||
|
await runCheckedAsync(
|
||||||
|
<String>[gradle, 'dependencies'],
|
||||||
|
workingDirectory: flutterProject.android.hostAppGradleRoot.path,
|
||||||
|
environment: _gradleEnv,
|
||||||
|
);
|
||||||
|
androidSdk.reinitialize();
|
||||||
|
progress.stop();
|
||||||
|
}
|
||||||
|
|
||||||
// Note: Dependencies are resolved and possibly downloaded as a side-effect
|
// Note: Dependencies are resolved and possibly downloaded as a side-effect
|
||||||
// of calculating the app properties using Gradle. This may take minutes.
|
// of calculating the app properties using Gradle. This may take minutes.
|
||||||
Future<GradleProject> _readGradleProject() async {
|
Future<GradleProject> _readGradleProject() async {
|
||||||
|
@ -34,6 +34,9 @@ class ApplicationPackageFactory {
|
|||||||
case TargetPlatform.android_arm64:
|
case TargetPlatform.android_arm64:
|
||||||
case TargetPlatform.android_x64:
|
case TargetPlatform.android_x64:
|
||||||
case TargetPlatform.android_x86:
|
case TargetPlatform.android_x86:
|
||||||
|
if (androidSdk?.licensesAvailable == true && androidSdk.latestVersion == null) {
|
||||||
|
await checkGradleDependencies();
|
||||||
|
}
|
||||||
return applicationBinary == null
|
return applicationBinary == null
|
||||||
? await AndroidApk.fromAndroidProject((await FlutterProject.current()).android)
|
? await AndroidApk.fromAndroidProject((await FlutterProject.current()).android)
|
||||||
: AndroidApk.fromApk(applicationBinary);
|
: AndroidApk.fromApk(applicationBinary);
|
||||||
|
@ -45,6 +45,15 @@ class UserMessages {
|
|||||||
String androidCantRunJavaBinary(String javaBinary) => 'Cannot execute $javaBinary to determine the version';
|
String androidCantRunJavaBinary(String javaBinary) => 'Cannot execute $javaBinary to determine the version';
|
||||||
String get androidUnknownJavaVersion => 'Could not determine java version';
|
String get androidUnknownJavaVersion => 'Could not determine java version';
|
||||||
String androidJavaVersion(String javaVersion) => 'Java version $javaVersion';
|
String androidJavaVersion(String javaVersion) => 'Java version $javaVersion';
|
||||||
|
String androidSdkLicenseOnly(String envKey) =>
|
||||||
|
'Android SDK contains licenses only.\n'
|
||||||
|
'Your first build of an Android application will take longer than usual, '
|
||||||
|
'while gradle downloads the missing components. This functionality will '
|
||||||
|
'only work if the licenses in the licenses folder in $envKey are valid.\n'
|
||||||
|
'If the Android SDK has been installed to another location, set $envKey to that location.\n'
|
||||||
|
'You may also want to add it to your PATH environment variable.\n\n'
|
||||||
|
'Certain features, such as `flutter emulators` and `flutter devices`, will '
|
||||||
|
'not work without the currently missing SDK components.';
|
||||||
String androidBadSdkDir(String envKey, String homeDir) =>
|
String androidBadSdkDir(String envKey, String homeDir) =>
|
||||||
'$envKey = $homeDir\n'
|
'$envKey = $homeDir\n'
|
||||||
'but Android SDK not found at this location.';
|
'but Android SDK not found at this location.';
|
||||||
@ -53,7 +62,7 @@ class UserMessages {
|
|||||||
'Install Android Studio from: https://developer.android.com/studio/index.html\n'
|
'Install Android Studio from: https://developer.android.com/studio/index.html\n'
|
||||||
'On first launch it will assist you in installing the Android SDK components.\n'
|
'On first launch it will assist you in installing the Android SDK components.\n'
|
||||||
'(or visit https://flutter.io/setup/#android-setup for detailed instructions).\n'
|
'(or visit https://flutter.io/setup/#android-setup for detailed instructions).\n'
|
||||||
'If Android SDK has been installed to a custom location, set $envKey to that location.\n'
|
'If the Android SDK has been installed to a custom location, set $envKey to that location.\n'
|
||||||
'You may also want to add it to your PATH environment variable.\n';
|
'You may also want to add it to your PATH environment variable.\n';
|
||||||
String androidSdkLocation(String directory) => 'Android SDK at $directory';
|
String androidSdkLocation(String directory) => 'Android SDK at $directory';
|
||||||
String androidSdkPlatformToolsVersion(String platform, String tools) =>
|
String androidSdkPlatformToolsVersion(String platform, String tools) =>
|
||||||
@ -75,7 +84,11 @@ class UserMessages {
|
|||||||
String get androidLicensesAll => 'All Android licenses accepted.';
|
String get androidLicensesAll => 'All Android licenses accepted.';
|
||||||
String get androidLicensesSome => 'Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses';
|
String get androidLicensesSome => 'Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses';
|
||||||
String get androidLicensesNone => 'Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses';
|
String get androidLicensesNone => 'Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses';
|
||||||
String get androidLicensesUnknown => 'Android license status unknown.';
|
String get androidLicensesUnknown =>
|
||||||
|
'Android license status unknown.\n'
|
||||||
|
'Try re-installing or updating your Android SDK Manager.\n'
|
||||||
|
'See https://developer.android.com/studio/#downloads or visit '
|
||||||
|
'https://flutter.io/setup/#android-setup for detailed instructions.';
|
||||||
String androidSdkManagerOutdated(String managerPath) =>
|
String androidSdkManagerOutdated(String managerPath) =>
|
||||||
'A newer version of the Android SDK is required. To update, run:\n'
|
'A newer version of the Android SDK is required. To update, run:\n'
|
||||||
'$managerPath --update\n';
|
'$managerPath --update\n';
|
||||||
|
@ -27,16 +27,23 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
group('getAdbDevices', () {
|
group('getAdbDevices', () {
|
||||||
|
final MockProcessManager mockProcessManager = MockProcessManager();
|
||||||
testUsingContext('throws on missing adb path', () {
|
testUsingContext('throws on missing adb path', () {
|
||||||
final Directory sdkDir = MockAndroidSdk.createSdkDirectory();
|
final Directory sdkDir = MockAndroidSdk.createSdkDirectory();
|
||||||
Config.instance.setValue('android-sdk', sdkDir.path);
|
Config.instance.setValue('android-sdk', sdkDir.path);
|
||||||
|
|
||||||
final File adbExe = fs.file(getAdbPath(androidSdk));
|
final File adbExe = fs.file(getAdbPath(androidSdk));
|
||||||
adbExe.deleteSync();
|
when(mockProcessManager.runSync(
|
||||||
|
<String>[adbExe.path, 'devices', '-l'],
|
||||||
|
))
|
||||||
|
.thenAnswer(
|
||||||
|
(_) => throw ArgumentError(adbExe.path),
|
||||||
|
);
|
||||||
expect(() => getAdbDevices(), throwsToolExit(message: RegExp('Unable to run "adb".*${adbExe.path}')));
|
expect(() => getAdbDevices(), throwsToolExit(message: RegExp('Unable to run "adb".*${adbExe.path}')));
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
AndroidSdk: () => MockAndroidSdk(),
|
AndroidSdk: () => MockAndroidSdk(),
|
||||||
FileSystem: () => MemoryFileSystem(),
|
FileSystem: () => MemoryFileSystem(),
|
||||||
|
ProcessManager: () => mockProcessManager,
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('physical devices', () {
|
testUsingContext('physical devices', () {
|
||||||
|
@ -226,6 +226,7 @@ class MockBrokenAndroidSdk extends Mock implements AndroidSdk {
|
|||||||
}) {
|
}) {
|
||||||
final Directory dir = fs.systemTempDirectory.createTempSync('flutter_mock_android_sdk.');
|
final Directory dir = fs.systemTempDirectory.createTempSync('flutter_mock_android_sdk.');
|
||||||
|
|
||||||
|
_createSdkFile(dir, 'licenses/dummy');
|
||||||
_createSdkFile(dir, 'platform-tools/adb');
|
_createSdkFile(dir, 'platform-tools/adb');
|
||||||
|
|
||||||
_createSdkFile(dir, 'build-tools/sda/aapt');
|
_createSdkFile(dir, 'build-tools/sda/aapt');
|
||||||
|
@ -42,11 +42,12 @@ void main() {
|
|||||||
return (List<String> command) => MockProcess(stdout: stdoutStream);
|
return (List<String> command) => MockProcess(stdout: stdoutStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
testUsingContext('licensesAccepted throws if cannot run sdkmanager', () async {
|
testUsingContext('licensesAccepted returns LicensesAccepted.unknown if cannot run sdkmanager', () async {
|
||||||
processManager.succeed = false;
|
processManager.succeed = false;
|
||||||
when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
|
when(sdk.sdkManagerPath).thenReturn('/foo/bar/sdkmanager');
|
||||||
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator();
|
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator();
|
||||||
expect(licenseValidator.licensesAccepted, throwsToolExit());
|
final LicensesAccepted licenseStatus = await licenseValidator.licensesAccepted;
|
||||||
|
expect(licenseStatus, LicensesAccepted.unknown);
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
AndroidSdk: () => sdk,
|
AndroidSdk: () => sdk,
|
||||||
FileSystem: () => fs,
|
FileSystem: () => fs,
|
||||||
@ -178,8 +179,27 @@ void main() {
|
|||||||
Stdio: () => stdio,
|
Stdio: () => stdio,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testUsingContext('detects license-only SDK installation', () async {
|
||||||
|
when(sdk.licensesAvailable).thenReturn(true);
|
||||||
|
when(sdk.platformToolsAvailable).thenReturn(false);
|
||||||
|
final ValidationResult validationResult = await AndroidValidator().validate();
|
||||||
|
expect(validationResult.type, ValidationType.partial);
|
||||||
|
expect(
|
||||||
|
validationResult.messages.last.message,
|
||||||
|
userMessages.androidSdkLicenseOnly(kAndroidHome),
|
||||||
|
);
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
AndroidSdk: () => sdk,
|
||||||
|
FileSystem: () => fs,
|
||||||
|
Platform: () => FakePlatform()..environment = <String, String>{'HOME': '/home/me'},
|
||||||
|
ProcessManager: () => processManager,
|
||||||
|
Stdio: () => stdio,
|
||||||
|
});
|
||||||
|
|
||||||
testUsingContext('detects minium required SDK and buildtools', () async {
|
testUsingContext('detects minium required SDK and buildtools', () async {
|
||||||
final AndroidSdkVersion mockSdkVersion = MockAndroidSdkVersion();
|
final AndroidSdkVersion mockSdkVersion = MockAndroidSdkVersion();
|
||||||
|
when(sdk.licensesAvailable).thenReturn(true);
|
||||||
|
when(sdk.platformToolsAvailable).thenReturn(true);
|
||||||
|
|
||||||
// Test with invalid SDK and build tools
|
// Test with invalid SDK and build tools
|
||||||
when(mockSdkVersion.sdkLevel).thenReturn(26);
|
when(mockSdkVersion.sdkLevel).thenReturn(26);
|
||||||
|
@ -3,18 +3,24 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io' show ProcessResult;
|
||||||
|
|
||||||
import 'package:file/file.dart';
|
import 'package:file/file.dart';
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:flutter_tools/src/base/platform.dart';
|
import 'package:flutter_tools/src/base/platform.dart';
|
||||||
|
import 'package:flutter_tools/src/build_info.dart';
|
||||||
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
|
import 'package:flutter_tools/src/project.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
|
|
||||||
import 'package:flutter_tools/src/application_package.dart';
|
import 'package:flutter_tools/src/application_package.dart';
|
||||||
|
import 'package:flutter_tools/src/android/android_sdk.dart';
|
||||||
import 'package:flutter_tools/src/base/context.dart';
|
import 'package:flutter_tools/src/base/context.dart';
|
||||||
import 'package:flutter_tools/src/base/file_system.dart';
|
import 'package:flutter_tools/src/base/file_system.dart';
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/base/os.dart';
|
import 'package:flutter_tools/src/base/os.dart';
|
||||||
import 'package:flutter_tools/src/ios/ios_workflow.dart';
|
import 'package:flutter_tools/src/ios/ios_workflow.dart';
|
||||||
|
import 'package:process/process.dart';
|
||||||
|
|
||||||
import 'src/common.dart';
|
import 'src/common.dart';
|
||||||
import 'src/context.dart';
|
import 'src/context.dart';
|
||||||
@ -24,7 +30,78 @@ final Map<Type, Generator> noColorTerminalOverride = <Type, Generator>{
|
|||||||
Platform: _kNoColorTerminalPlatform,
|
Platform: _kNoColorTerminalPlatform,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MockitoProcessManager extends Mock implements ProcessManager {}
|
||||||
|
class MockitoAndroidSdk extends Mock implements AndroidSdk {}
|
||||||
|
class MockitoAndroidSdkVersion extends Mock implements AndroidSdkVersion {}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
group('Apk with partial Android SDK works', () {
|
||||||
|
AndroidSdk sdk;
|
||||||
|
ProcessManager mockProcessManager;
|
||||||
|
MemoryFileSystem fs;
|
||||||
|
File gradle;
|
||||||
|
final Map<Type, Generator> overrides = <Type, Generator>{
|
||||||
|
AndroidSdk: () => sdk,
|
||||||
|
ProcessManager: () => mockProcessManager,
|
||||||
|
FileSystem: () => fs,
|
||||||
|
};
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
sdk = MockitoAndroidSdk();
|
||||||
|
mockProcessManager = MockitoProcessManager();
|
||||||
|
fs = MemoryFileSystem();
|
||||||
|
Cache.flutterRoot = '../..';
|
||||||
|
when(sdk.licensesAvailable).thenReturn(true);
|
||||||
|
when(mockProcessManager.canRun(any)).thenReturn(true);
|
||||||
|
when(mockProcessManager.run(
|
||||||
|
any,
|
||||||
|
workingDirectory: anyNamed('workingDirectory'),
|
||||||
|
environment: anyNamed('environment'),
|
||||||
|
)).thenAnswer((_) async => ProcessResult(1, 0, 'stdout', 'stderr'));
|
||||||
|
when(mockProcessManager.runSync(any)).thenReturn(ProcessResult(1, 0, 'stdout', 'stderr'));
|
||||||
|
final FlutterProject project = await FlutterProject.current();
|
||||||
|
gradle = fs.file(project.android.hostAppGradleRoot.childFile(
|
||||||
|
platform.isWindows ? 'gradlew.bat' : 'gradlew',
|
||||||
|
).path)..createSync(recursive: true);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('Licenses available, build tools not, apk exists', () async {
|
||||||
|
when(sdk.latestVersion).thenReturn(null);
|
||||||
|
final FlutterProject project = await FlutterProject.current();
|
||||||
|
final File gradle = project.android.hostAppGradleRoot.childFile(
|
||||||
|
platform.isWindows ? 'gradlew.bat' : 'gradlew',
|
||||||
|
)..createSync(recursive: true);
|
||||||
|
|
||||||
|
await ApplicationPackageFactory.instance.getPackageForPlatform(
|
||||||
|
TargetPlatform.android_arm,
|
||||||
|
applicationBinary: fs.file('app.apk'),
|
||||||
|
);
|
||||||
|
verify(
|
||||||
|
mockProcessManager.run(
|
||||||
|
argThat(equals(<String>[gradle.path, 'dependencies'])),
|
||||||
|
workingDirectory: anyNamed('workingDirectory'),
|
||||||
|
environment: anyNamed('environment'),
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
}, overrides: overrides);
|
||||||
|
|
||||||
|
testUsingContext('Licenses available, build tools available, does not call gradle dependencies', () async {
|
||||||
|
final AndroidSdkVersion sdkVersion = MockitoAndroidSdkVersion();
|
||||||
|
when(sdk.latestVersion).thenReturn(sdkVersion);
|
||||||
|
|
||||||
|
await ApplicationPackageFactory.instance.getPackageForPlatform(
|
||||||
|
TargetPlatform.android_arm,
|
||||||
|
);
|
||||||
|
verifyNever(
|
||||||
|
mockProcessManager.run(
|
||||||
|
argThat(equals(<String>[gradle.path, 'dependencies'])),
|
||||||
|
workingDirectory: anyNamed('workingDirectory'),
|
||||||
|
environment: anyNamed('environment'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}, overrides: overrides);
|
||||||
|
});
|
||||||
|
|
||||||
group('ApkManifestData', () {
|
group('ApkManifestData', () {
|
||||||
test('Parses manifest with an Activity that has enabled set to true, action set to android.intent.action.MAIN and category set to android.intent.category.LAUNCHER', () {
|
test('Parses manifest with an Activity that has enabled set to true, action set to android.intent.action.MAIN and category set to android.intent.category.LAUNCHER', () {
|
||||||
final ApkManifestData data = ApkManifestData.parseFromXmlDump(_aaptDataWithExplicitEnabledAndMainLauncherActivity);
|
final ApkManifestData data = ApkManifestData.parseFromXmlDump(_aaptDataWithExplicitEnabledAndMainLauncherActivity);
|
||||||
|
@ -44,16 +44,24 @@ class MockAndroidSdk extends Mock implements AndroidSdk {
|
|||||||
int ndkVersion = 16,
|
int ndkVersion = 16,
|
||||||
bool withNdkSysroot = false,
|
bool withNdkSysroot = false,
|
||||||
bool withSdkManager = true,
|
bool withSdkManager = true,
|
||||||
|
bool withPlatformTools = true,
|
||||||
|
bool withBuildTools = true,
|
||||||
}) {
|
}) {
|
||||||
final Directory dir = fs.systemTempDirectory.createTempSync('flutter_mock_android_sdk.');
|
final Directory dir = fs.systemTempDirectory.createTempSync('flutter_mock_android_sdk.');
|
||||||
|
|
||||||
_createSdkFile(dir, 'platform-tools/adb');
|
_createDir(dir, 'licenses');
|
||||||
|
|
||||||
|
if (withPlatformTools) {
|
||||||
|
_createSdkFile(dir, 'platform-tools/adb');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (withBuildTools) {
|
||||||
_createSdkFile(dir, 'build-tools/19.1.0/aapt');
|
_createSdkFile(dir, 'build-tools/19.1.0/aapt');
|
||||||
_createSdkFile(dir, 'build-tools/22.0.1/aapt');
|
_createSdkFile(dir, 'build-tools/22.0.1/aapt');
|
||||||
_createSdkFile(dir, 'build-tools/23.0.2/aapt');
|
_createSdkFile(dir, 'build-tools/23.0.2/aapt');
|
||||||
if (withAndroidN)
|
if (withAndroidN)
|
||||||
_createSdkFile(dir, 'build-tools/24.0.0-preview/aapt');
|
_createSdkFile(dir, 'build-tools/24.0.0-preview/aapt');
|
||||||
|
}
|
||||||
|
|
||||||
_createSdkFile(dir, 'platforms/android-22/android.jar');
|
_createSdkFile(dir, 'platforms/android-22/android.jar');
|
||||||
_createSdkFile(dir, 'platforms/android-23/android.jar');
|
_createSdkFile(dir, 'platforms/android-23/android.jar');
|
||||||
|
Loading…
Reference in New Issue
Block a user