Unverified Commit 97a9f2ae authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] move gradle helper methods into AndroidBuilder class body,...

[flutter_tools] move gradle helper methods into AndroidBuilder class body, split unit tests (#75931)
parent fb808b40
...@@ -6,21 +6,15 @@ ...@@ -6,21 +6,15 @@
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../android/gradle_errors.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../base/file_system.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../globals.dart' as globals;
import '../project.dart'; import '../project.dart';
import 'gradle.dart';
/// The builder in the current context. /// The builder in the current context.
AndroidBuilder get androidBuilder { AndroidBuilder get androidBuilder {
return context.get<AndroidBuilder>() ?? const _AndroidBuilderImpl(); return context.get<AndroidBuilder>();
} }
/// Provides the methods to build Android artifacts.
// TODO(egarciad): https://github.com/flutter/flutter/issues/43863
abstract class AndroidBuilder { abstract class AndroidBuilder {
const AndroidBuilder(); const AndroidBuilder();
/// Builds an AAR artifact. /// Builds an AAR artifact.
...@@ -46,89 +40,3 @@ abstract class AndroidBuilder { ...@@ -46,89 +40,3 @@ abstract class AndroidBuilder {
@required String target, @required String target,
}); });
} }
/// Default implementation of [AarBuilder].
class _AndroidBuilderImpl extends AndroidBuilder {
const _AndroidBuilderImpl();
/// Builds the AAR and POM files for the current Flutter module or plugin.
@override
Future<void> buildAar({
@required FlutterProject project,
@required Set<AndroidBuildInfo> androidBuildInfo,
@required String target,
@required String outputDirectoryPath,
@required String buildNumber,
}) async {
try {
Directory outputDirectory =
globals.fs.directory(outputDirectoryPath ?? project.android.buildDirectory);
if (project.isModule) {
// Module projects artifacts are located in `build/host`.
outputDirectory = outputDirectory.childDirectory('host');
}
for (final AndroidBuildInfo androidBuildInfo in androidBuildInfo) {
await buildGradleAar(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
outputDirectory: outputDirectory,
buildNumber: buildNumber,
);
}
printHowToConsumeAar(
buildModes: androidBuildInfo
.map<String>((AndroidBuildInfo androidBuildInfo) {
return androidBuildInfo.buildInfo.modeName;
}).toSet(),
androidPackage: project.manifest.androidPackage,
repoDirectory: getRepoDirectory(outputDirectory),
buildNumber: buildNumber,
logger: globals.logger,
fileSystem: globals.fs,
);
} finally {
globals.androidSdk?.reinitialize();
}
}
/// Builds the APK.
@override
Future<void> buildApk({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
}) async {
try {
await buildGradleApp(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
isBuildingBundle: false,
localGradleErrors: gradleErrors,
);
} finally {
globals.androidSdk?.reinitialize();
}
}
/// Builds the App Bundle.
@override
Future<void> buildAab({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
}) async {
try {
await buildGradleApp(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
isBuildingBundle: true,
localGradleErrors: gradleErrors,
);
} finally {
globals.androidSdk?.reinitialize();
}
}
}
...@@ -24,6 +24,7 @@ import '../flutter_manifest.dart'; ...@@ -24,6 +24,7 @@ import '../flutter_manifest.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../project.dart'; import '../project.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
import 'android_builder.dart';
import 'gradle_errors.dart'; import 'gradle_errors.dart';
import 'gradle_utils.dart'; import 'gradle_utils.dart';
...@@ -202,18 +203,101 @@ void createSettingsAarGradle(Directory androidDirectory) { ...@@ -202,18 +203,101 @@ void createSettingsAarGradle(Directory androidDirectory) {
globals.printStatus('$successMark `$newSettingsRelativeFile` created successfully.'); globals.printStatus('$successMark `$newSettingsRelativeFile` created successfully.');
} }
/// Builds an app. /// An implementation of the [AndroidBuilder] that delegates to gradle.
/// class AndroidGradleBuilder implements AndroidBuilder {
/// * [project] is typically [FlutterProject.current()]. /// Builds the AAR and POM files for the current Flutter module or plugin.
/// * [androidBuildInfo] is the build configuration. @override
/// * [target] is the target dart entry point. Typically, `lib/main.dart`. Future<void> buildAar({
/// * If [isBuildingBundle] is `true`, then the output artifact is an `*.aab`, @required FlutterProject project,
/// otherwise the output artifact is an `*.apk`. @required Set<AndroidBuildInfo> androidBuildInfo,
/// * The plugins are built as AARs if [shouldBuildPluginAsAar] is `true`. This isn't set by default @required String target,
/// because it makes the build slower proportional to the number of plugins. @required String outputDirectoryPath,
/// * [retries] is the max number of build retries in case one of the [GradleHandledError] handler @required String buildNumber,
/// returns [GradleBuildStatus.retry] or [GradleBuildStatus.retryWithAarPlugins]. }) async {
Future<void> buildGradleApp({ try {
Directory outputDirectory =
globals.fs.directory(outputDirectoryPath ?? project.android.buildDirectory);
if (project.isModule) {
// Module projects artifacts are located in `build/host`.
outputDirectory = outputDirectory.childDirectory('host');
}
for (final AndroidBuildInfo androidBuildInfo in androidBuildInfo) {
await buildGradleAar(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
outputDirectory: outputDirectory,
buildNumber: buildNumber,
);
}
printHowToConsumeAar(
buildModes: androidBuildInfo
.map<String>((AndroidBuildInfo androidBuildInfo) {
return androidBuildInfo.buildInfo.modeName;
}).toSet(),
androidPackage: project.manifest.androidPackage,
repoDirectory: getRepoDirectory(outputDirectory),
buildNumber: buildNumber,
logger: globals.logger,
fileSystem: globals.fs,
);
} finally {
globals.androidSdk?.reinitialize();
}
}
/// Builds the APK.
@override
Future<void> buildApk({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
}) async {
try {
await buildGradleApp(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
isBuildingBundle: false,
localGradleErrors: gradleErrors,
);
} finally {
globals.androidSdk?.reinitialize();
}
}
/// Builds the App Bundle.
@override
Future<void> buildAab({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
}) async {
try {
await buildGradleApp(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
isBuildingBundle: true,
localGradleErrors: gradleErrors,
);
} finally {
globals.androidSdk?.reinitialize();
}
}
/// Builds an app.
///
/// * [project] is typically [FlutterProject.current()].
/// * [androidBuildInfo] is the build configuration.
/// * [target] is the target dart entry point. Typically, `lib/main.dart`.
/// * If [isBuildingBundle] is `true`, then the output artifact is an `*.aab`,
/// otherwise the output artifact is an `*.apk`.
/// * The plugins are built as AARs if [shouldBuildPluginAsAar] is `true`. This isn't set by default
/// because it makes the build slower proportional to the number of plugins.
/// * [retries] is the max number of build retries in case one of the [GradleHandledError] handler
/// returns [GradleBuildStatus.retry] or [GradleBuildStatus.retryWithAarPlugins].
Future<void> buildGradleApp({
@required FlutterProject project, @required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo, @required AndroidBuildInfo androidBuildInfo,
@required String target, @required String target,
...@@ -221,7 +305,7 @@ Future<void> buildGradleApp({ ...@@ -221,7 +305,7 @@ Future<void> buildGradleApp({
@required List<GradleHandledError> localGradleErrors, @required List<GradleHandledError> localGradleErrors,
bool shouldBuildPluginAsAar = false, bool shouldBuildPluginAsAar = false,
int retries = 1, int retries = 1,
}) async { }) async {
assert(project != null); assert(project != null);
assert(androidBuildInfo != null); assert(androidBuildInfo != null);
assert(target != null); assert(target != null);
...@@ -356,7 +440,8 @@ Future<void> buildGradleApp({ ...@@ -356,7 +440,8 @@ Future<void> buildGradleApp({
return line; return line;
} }
final Stopwatch sw = Stopwatch()..start(); final Stopwatch sw = Stopwatch()
..start();
int exitCode = 1; int exitCode = 1;
try { try {
exitCode = await globals.processUtils.stream( exitCode = await globals.processUtils.stream(
...@@ -464,7 +549,9 @@ Future<void> buildGradleApp({ ...@@ -464,7 +549,9 @@ Future<void> buildGradleApp({
// Copy the first APK to app.apk, so `flutter run` can find it. // Copy the first APK to app.apk, so `flutter run` can find it.
// TODO(egarciad): Handle multiple APKs. // TODO(egarciad): Handle multiple APKs.
apkFile.copySync(apkDirectory.childFile('app.apk').path); apkFile.copySync(apkDirectory
.childFile('app.apk')
.path);
globals.printTrace('calculateSha: $apkDirectory/app.apk'); globals.printTrace('calculateSha: $apkDirectory/app.apk');
final File apkShaFile = apkDirectory.childFile('app.apk.sha1'); final File apkShaFile = apkDirectory.childFile('app.apk.sha1');
...@@ -481,13 +568,11 @@ Future<void> buildGradleApp({ ...@@ -481,13 +568,11 @@ Future<void> buildGradleApp({
if (buildInfo.codeSizeDirectory != null) { if (buildInfo.codeSizeDirectory != null) {
await _performCodeSizeAnalysis('apk', apkFile, androidBuildInfo); await _performCodeSizeAnalysis('apk', apkFile, androidBuildInfo);
} }
} }
Future<void> _performCodeSizeAnalysis( Future<void> _performCodeSizeAnalysis(String kind,
String kind,
File zipFile, File zipFile,
AndroidBuildInfo androidBuildInfo, AndroidBuildInfo androidBuildInfo,) async {
) async {
final SizeAnalyzer sizeAnalyzer = SizeAnalyzer( final SizeAnalyzer sizeAnalyzer = SizeAnalyzer(
fileSystem: globals.fs, fileSystem: globals.fs,
logger: globals.logger, logger: globals.logger,
...@@ -509,34 +594,38 @@ Future<void> _performCodeSizeAnalysis( ...@@ -509,34 +594,38 @@ Future<void> _performCodeSizeAnalysis(
globals.fs globals.fs
.directory(globals.fsUtils.homeDirPath) .directory(globals.fsUtils.homeDirPath)
.childDirectory('.flutter-devtools'), '$kind-code-size-analysis', 'json', .childDirectory('.flutter-devtools'), '$kind-code-size-analysis', 'json',
)..writeAsStringSync(jsonEncode(output)); )
..writeAsStringSync(jsonEncode(output));
// This message is used as a sentinel in analyze_apk_size_test.dart // This message is used as a sentinel in analyze_apk_size_test.dart
globals.printStatus( globals.printStatus(
'A summary of your ${kind.toUpperCase()} analysis can be found at: ${outputFile.path}', 'A summary of your ${kind.toUpperCase()} analysis can be found at: ${outputFile.path}',
); );
// DevTools expects a file path relative to the .flutter-devtools/ dir. // DevTools expects a file path relative to the .flutter-devtools/ dir.
final String relativeAppSizePath = outputFile.path.split('.flutter-devtools/').last.trim(); final String relativeAppSizePath = outputFile.path
.split('.flutter-devtools/')
.last
.trim();
globals.printStatus( globals.printStatus(
'\nTo analyze your app size in Dart DevTools, run the following command:\n' '\nTo analyze your app size in Dart DevTools, run the following command:\n'
'flutter pub global activate devtools; flutter pub global run devtools ' 'flutter pub global activate devtools; flutter pub global run devtools '
'--appSizeBase=$relativeAppSizePath' '--appSizeBase=$relativeAppSizePath'
); );
} }
/// Builds AAR and POM files. /// Builds AAR and POM files.
/// ///
/// * [project] is typically [FlutterProject.current()]. /// * [project] is typically [FlutterProject.current()].
/// * [androidBuildInfo] is the build configuration. /// * [androidBuildInfo] is the build configuration.
/// * [outputDir] is the destination of the artifacts, /// * [outputDir] is the destination of the artifacts,
/// * [buildNumber] is the build number of the output aar, /// * [buildNumber] is the build number of the output aar,
Future<void> buildGradleAar({ Future<void> buildGradleAar({
@required FlutterProject project, @required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo, @required AndroidBuildInfo androidBuildInfo,
@required String target, @required String target,
@required Directory outputDirectory, @required Directory outputDirectory,
@required String buildNumber, @required String buildNumber,
}) async { }) async {
assert(project != null); assert(project != null);
assert(target != null); assert(target != null);
assert(androidBuildInfo != null); assert(androidBuildInfo != null);
...@@ -611,7 +700,7 @@ Future<void> buildGradleAar({ ...@@ -611,7 +700,7 @@ Future<void> buildGradleAar({
localEngineRepo, localEngineRepo,
getRepoDirectory(outputDirectory), getRepoDirectory(outputDirectory),
); );
} on FileSystemException catch(_) { } on FileSystemException catch (_) {
throwToolExit( throwToolExit(
'Failed to copy the local engine ${localEngineRepo.path} repo ' 'Failed to copy the local engine ${localEngineRepo.path} repo '
'in ${outputDirectory.path}' 'in ${outputDirectory.path}'
...@@ -627,7 +716,8 @@ Future<void> buildGradleAar({ ...@@ -627,7 +716,8 @@ Future<void> buildGradleAar({
command.add(aarTask); command.add(aarTask);
final Stopwatch sw = Stopwatch()..start(); final Stopwatch sw = Stopwatch()
..start();
RunResult result; RunResult result;
try { try {
result = await globals.processUtils.run( result = await globals.processUtils.run(
...@@ -662,6 +752,59 @@ Future<void> buildGradleAar({ ...@@ -662,6 +752,59 @@ Future<void> buildGradleAar({
'$successMark Built ${globals.fs.path.relative(repoDirectory.path)}.', '$successMark Built ${globals.fs.path.relative(repoDirectory.path)}.',
color: TerminalColor.green, color: TerminalColor.green,
); );
}
/// Builds the plugins as AARs.
@visibleForTesting
Future<void> buildPluginsAsAar(
FlutterProject flutterProject,
AndroidBuildInfo androidBuildInfo, {
Directory buildDirectory,
}) async {
final File flutterPluginFile = flutterProject.flutterPluginsFile;
if (!flutterPluginFile.existsSync()) {
return;
}
final List<String> plugins = flutterPluginFile.readAsStringSync().split('\n');
for (final String plugin in plugins) {
final List<String> pluginParts = plugin.split('=');
if (pluginParts.length != 2) {
continue;
}
final Directory pluginDirectory = globals.fs.directory(pluginParts.last);
assert(pluginDirectory.existsSync());
final String pluginName = pluginParts.first;
final File buildGradleFile = pluginDirectory.childDirectory('android').childFile('build.gradle');
if (!buildGradleFile.existsSync()) {
globals.printTrace("Skipping plugin $pluginName since it doesn't have a android/build.gradle file");
continue;
}
globals.logger.printStatus('Building plugin $pluginName...');
try {
await buildGradleAar(
project: FlutterProject.fromDirectory(pluginDirectory),
androidBuildInfo: AndroidBuildInfo(
BuildInfo(
BuildMode.release, // Plugins are built as release.
null, // Plugins don't define flavors.
treeShakeIcons: androidBuildInfo.buildInfo.treeShakeIcons,
packagesPath: androidBuildInfo.buildInfo.packagesPath,
),
),
target: '',
outputDirectory: buildDirectory,
buildNumber: '1.0'
);
} on ToolExit {
// Log the entire plugin entry in `.flutter-plugins` since it
// includes the plugin name and the version.
BuildEvent('gradle-plugin-aar-failure', eventError: plugin, flutterUsage: globals.flutterUsage).send();
throwToolExit('The plugin $pluginName could not be built due to the issue above.');
}
}
}
} }
/// Prints how to consume the AAR from a host app. /// Prints how to consume the AAR from a host app.
...@@ -774,57 +917,6 @@ bool isAppUsingAndroidX(Directory androidDirectory) { ...@@ -774,57 +917,6 @@ bool isAppUsingAndroidX(Directory androidDirectory) {
return properties.readAsStringSync().contains('android.useAndroidX=true'); return properties.readAsStringSync().contains('android.useAndroidX=true');
} }
/// Builds the plugins as AARs.
@visibleForTesting
Future<void> buildPluginsAsAar(
FlutterProject flutterProject,
AndroidBuildInfo androidBuildInfo, {
Directory buildDirectory,
}) async {
final File flutterPluginFile = flutterProject.flutterPluginsFile;
if (!flutterPluginFile.existsSync()) {
return;
}
final List<String> plugins = flutterPluginFile.readAsStringSync().split('\n');
for (final String plugin in plugins) {
final List<String> pluginParts = plugin.split('=');
if (pluginParts.length != 2) {
continue;
}
final Directory pluginDirectory = globals.fs.directory(pluginParts.last);
assert(pluginDirectory.existsSync());
final String pluginName = pluginParts.first;
final File buildGradleFile = pluginDirectory.childDirectory('android').childFile('build.gradle');
if (!buildGradleFile.existsSync()) {
globals.printTrace("Skipping plugin $pluginName since it doesn't have a android/build.gradle file");
continue;
}
globals.logger.printStatus('Building plugin $pluginName...');
try {
await buildGradleAar(
project: FlutterProject.fromDirectory(pluginDirectory),
androidBuildInfo: AndroidBuildInfo(
BuildInfo(
BuildMode.release, // Plugins are built as release.
null, // Plugins don't define flavors.
treeShakeIcons: androidBuildInfo.buildInfo.treeShakeIcons,
packagesPath: androidBuildInfo.buildInfo.packagesPath,
),
),
target: '',
outputDirectory: buildDirectory,
buildNumber: '1.0'
);
} on ToolExit {
// Log the entire plugin entry in `.flutter-plugins` since it
// includes the plugin name and the version.
BuildEvent('gradle-plugin-aar-failure', eventError: plugin, flutterUsage: globals.flutterUsage).send();
throwToolExit('The plugin $pluginName could not be built due to the issue above.');
}
}
}
/// Returns the APK files for a given [FlutterProject] and [AndroidBuildInfo]. /// Returns the APK files for a given [FlutterProject] and [AndroidBuildInfo].
@visibleForTesting @visibleForTesting
Iterable<String> findApkFilesModule( Iterable<String> findApkFilesModule(
......
...@@ -8,9 +8,11 @@ import 'dart:async'; ...@@ -8,9 +8,11 @@ import 'dart:async';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'android/android_builder.dart';
import 'android/android_sdk.dart'; import 'android/android_sdk.dart';
import 'android/android_studio.dart'; import 'android/android_studio.dart';
import 'android/android_workflow.dart'; import 'android/android_workflow.dart';
import 'android/gradle.dart';
import 'android/gradle_utils.dart'; import 'android/gradle_utils.dart';
import 'application_package.dart'; import 'application_package.dart';
import 'artifacts.dart'; import 'artifacts.dart';
...@@ -77,6 +79,7 @@ Future<T> runInContext<T>( ...@@ -77,6 +79,7 @@ Future<T> runInContext<T>(
body: runnerWrapper, body: runnerWrapper,
overrides: overrides, overrides: overrides,
fallbacks: <Type, Generator>{ fallbacks: <Type, Generator>{
AndroidBuilder: () => AndroidGradleBuilder(),
AndroidLicenseValidator: () => AndroidLicenseValidator( AndroidLicenseValidator: () => AndroidLicenseValidator(
operatingSystemUtils: globals.os, operatingSystemUtils: globals.os,
platform: globals.platform, platform: globals.platform,
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:archive/archive.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/android/android_studio.dart';
import 'package:flutter_tools/src/android/gradle.dart';
import 'package:flutter_tools/src/android/gradle_errors.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.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/globals.dart' as globals;
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart';
void main() {
group('gradle build', () {
TestUsage testUsage;
MockAndroidSdk mockAndroidSdk;
MockAndroidStudio mockAndroidStudio;
MockLocalEngineArtifacts mockArtifacts;
MockProcessManager mockProcessManager;
FakePlatform android;
FileSystem fileSystem;
FileSystemUtils fileSystemUtils;
Cache cache;
AndroidGradleBuilder builder;
setUp(() {
testUsage = TestUsage();
fileSystem = MemoryFileSystem.test();
fileSystemUtils = MockFileSystemUtils();
mockAndroidSdk = MockAndroidSdk();
mockAndroidStudio = MockAndroidStudio();
mockArtifacts = MockLocalEngineArtifacts();
mockProcessManager = MockProcessManager();
android = fakePlatform('android');
builder = AndroidGradleBuilder();
when(mockAndroidSdk.directory).thenReturn('irrelevant');
final Directory rootDirectory = fileSystem.currentDirectory;
cache = Cache.test(
rootOverride: rootDirectory,
fileSystem: fileSystem,
);
final Directory gradleWrapperDirectory = rootDirectory
.childDirectory('bin')
.childDirectory('cache')
.childDirectory('artifacts')
.childDirectory('gradle_wrapper');
gradleWrapperDirectory.createSync(recursive: true);
gradleWrapperDirectory
.childFile('gradlew')
.writeAsStringSync('irrelevant');
gradleWrapperDirectory
.childDirectory('gradle')
.childDirectory('wrapper')
.createSync(recursive: true);
gradleWrapperDirectory
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.jar')
.writeAsStringSync('irrelevant');
});
testUsingContext('recognizes common errors - tool exit', () async {
final Process process = createMockProcess(
exitCode: 1,
stdout: 'irrelevant\nSome gradle message\nirrelevant',
);
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) => Future<Process>.value(process));
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
bool handlerCalled = false;
await expectLater(() async {
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[
GradleHandledError(
test: (String line) {
return line.contains('Some gradle message');
},
handler: ({
String line,
FlutterProject project,
bool usesAndroidX,
bool shouldBuildPluginAsAar,
}) async {
handlerCalled = true;
return GradleBuildStatus.exit;
},
eventLabel: 'random-event-label',
),
],
);
},
throwsToolExit(
message: 'Gradle task assembleRelease failed with exit code 1'
));
expect(handlerCalled, isTrue);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('recognizes common errors - retry build', () async {
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
final Process process = createMockProcess(
exitCode: 1,
stdout: 'irrelevant\nSome gradle message\nirrelevant',
);
return Future<Process>.value(process);
});
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
int testFnCalled = 0;
await expectLater(() async {
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[
GradleHandledError(
test: (String line) {
if (line.contains('Some gradle message')) {
testFnCalled++;
return true;
}
return false;
},
handler: ({
String line,
FlutterProject project,
bool usesAndroidX,
bool shouldBuildPluginAsAar,
}) async {
return GradleBuildStatus.retry;
},
eventLabel: 'random-event-label',
),
],
);
}, throwsToolExit(
message: 'Gradle task assembleRelease failed with exit code 1'
));
expect(testFnCalled, equals(2));
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('recognizes process exceptions - tool exit', () async {
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenThrow(const ProcessException('', <String>[], 'Some gradle message'));
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
bool handlerCalled = false;
await expectLater(() async {
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[
GradleHandledError(
test: (String line) {
return line.contains('Some gradle message');
},
handler: ({
String line,
FlutterProject project,
bool usesAndroidX,
bool shouldBuildPluginAsAar,
}) async {
handlerCalled = true;
return GradleBuildStatus.exit;
},
eventLabel: 'random-event-label',
),
],
);
},
throwsToolExit(
message: 'Gradle task assembleRelease failed with exit code 1'
));
expect(handlerCalled, isTrue);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('rethrows unrecognized ProcessException', () async {
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenThrow(const ProcessException('', <String>[], 'Unrecognized'));
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
await expectLater(() async {
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
},
throwsA(isA<ProcessException>()));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext('logs success event after a successful retry', () async {
int testFnCalled = 0;
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
Process process;
if (testFnCalled == 0) {
process = createMockProcess(
exitCode: 1,
stdout: 'irrelevant\nSome gradle message\nirrelevant',
);
} else {
process = createMockProcess(
exitCode: 0,
stdout: 'irrelevant',
);
}
testFnCalled++;
return Future<Process>.value(process);
});
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
fileSystem.directory('build')
.childDirectory('app')
.childDirectory('outputs')
.childDirectory('flutter-apk')
.childFile('app-release.apk')
.createSync(recursive: true);
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[
GradleHandledError(
test: (String line) {
return line.contains('Some gradle message');
},
handler: ({
String line,
FlutterProject project,
bool usesAndroidX,
bool shouldBuildPluginAsAar,
}) async {
return GradleBuildStatus.retry;
},
eventLabel: 'random-event-label',
),
],
);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-success',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
FileSystem: () => fileSystem,
Platform: () => android,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('performs code size analysis and sends analytics', () async {
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
return Future<Process>.value(createMockProcess(
exitCode: 0,
stdout: 'irrelevant',
));
});
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
final Archive archive = Archive()
..addFile(ArchiveFile('AndroidManifest.xml', 100, List<int>.filled(100, 0)))
..addFile(ArchiveFile('META-INF/CERT.RSA', 10, List<int>.filled(10, 0)))
..addFile(ArchiveFile('META-INF/CERT.SF', 10, List<int>.filled(10, 0)))
..addFile(ArchiveFile('lib/arm64-v8a/libapp.so', 50, List<int>.filled(50, 0)))
..addFile(ArchiveFile('lib/arm64-v8a/libflutter.so', 50, List<int>.filled(50, 0)));
fileSystem.directory('build')
.childDirectory('app')
.childDirectory('outputs')
.childDirectory('flutter-apk')
.childFile('app-release.apk')
..createSync(recursive: true)
..writeAsBytesSync(ZipEncoder().encode(archive));
fileSystem.file('foo/snapshot.arm64-v8a.json')
..createSync(recursive: true)
..writeAsStringSync(r'''
[
{
"l": "dart:_internal",
"c": "SubListIterable",
"n": "[Optimized] skip",
"s": 2400
}
]''');
fileSystem.file('foo/trace.arm64-v8a.json')
..createSync(recursive: true)
..writeAsStringSync('{}');
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
codeSizeDirectory: 'foo',
),
targetArchs: <AndroidArch>[AndroidArch.arm64_v8a],
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[],
);
expect(testUsage.events, contains(
const TestUsageEvent(
'code-size-analysis',
'apk',
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
FileSystem: () => fileSystem,
Platform: () => android,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('recognizes common errors - retry build with AAR plugins', () async {
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
final Process process = createMockProcess(
exitCode: 1,
stdout: 'irrelevant\nSome gradle message\nirrelevant',
);
return Future<Process>.value(process);
});
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
int testFnCalled = 0;
bool builtPluginAsAar = false;
await expectLater(() async {
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[
GradleHandledError(
test: (String line) {
if (line.contains('Some gradle message')) {
testFnCalled++;
return true;
}
return false;
},
handler: ({
String line,
FlutterProject project,
bool usesAndroidX,
bool shouldBuildPluginAsAar,
}) async {
if (testFnCalled == 2) {
builtPluginAsAar = shouldBuildPluginAsAar;
}
return GradleBuildStatus.retryWithAarPlugins;
},
eventLabel: 'random-event-label',
),
],
);
}, throwsToolExit(
message: 'Gradle task assembleRelease failed with exit code 1'
));
expect(testFnCalled, equals(2));
expect(builtPluginAsAar, isTrue);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('indicates that an APK has been built successfully', () async {
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
fileSystem.directory('build')
.childDirectory('app')
.childDirectory('outputs')
.childDirectory('flutter-apk')
.childFile('app-release.apk')
.createSync(recursive: true);
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
expect(
testLogger.statusText,
contains('Built build/app/outputs/flutter-apk/app-release.apk (0.0MB)'),
);
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
FileSystem: () => fileSystem,
Platform: () => android,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext("doesn't indicate how to consume an AAR when printHowToConsumeAaar is false", () async {
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
await builder.buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '1.0',
);
expect(
testLogger.statusText,
contains('Built build/outputs/repo'),
);
expect(
testLogger.statusText.contains('Consuming the Module'),
isFalse,
);
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext('gradle exit code is properly passed on', () async {
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 108, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
await expectLater(() async =>
await builder.buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '1.0',
)
, throwsToolExit(exitCode: 108, message: 'Gradle task assembleAarRelease failed with exit code 108.'));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext('build apk uses selected local engine,the engine abi is arm', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: TargetPlatform.android_arm,
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_arm'));
fileSystem.file('out/android_arm/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_arm/armeabi_v7a_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm/armeabi_v7a_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm/armeabi_v7a_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('android/gradlew').createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.file('android/build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
return Future<Process>.value(
createMockProcess(
exitCode: 1,
)
);
});
await expectLater(() async {
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
}, throwsToolExit());
final List<String> actualGradlewCall = verify(
mockProcessManager.start(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build apk uses selected local engine,the engine abi is arm64', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_arm64'));
fileSystem.file('out/android_arm64/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_arm64/arm64_v8a_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm64/arm64_v8a_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm64/arm64_v8a_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('android/gradlew').createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.file('android/build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
return Future<Process>.value(
createMockProcess(
exitCode: 1,
)
);
});
await expectLater(() async {
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
}, throwsToolExit());
final List<String> actualGradlewCall = verify(
mockProcessManager.start(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm64'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build apk uses selected local engine,the engine abi is x86', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_x86'));
fileSystem.file('out/android_x86/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_x86/x86_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x86/x86_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x86/x86_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('android/gradlew').createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.file('android/build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
return Future<Process>.value(
createMockProcess(
exitCode: 1,
)
);
});
await expectLater(() async {
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
}, throwsToolExit());
final List<String> actualGradlewCall = verify(
mockProcessManager.start(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x86'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build apk uses selected local engine,the engine abi is x64', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_x64'));
fileSystem.file('out/android_x64/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_x64/x86_64_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x64/x86_64_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x64/x86_64_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('android/gradlew').createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.file('android/build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
return Future<Process>.value(
createMockProcess(
exitCode: 1,
)
);
});
await expectLater(() async {
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
}, throwsToolExit());
final List<String> actualGradlewCall = verify(
mockProcessManager.start(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x64'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext('honors --no-android-gradle-daemon setting', () async {
(globals.processManager as FakeProcessManager).addCommand(
const FakeCommand(command: <String>[
'/android/gradlew',
'-q',
'--no-daemon',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
'assembleRelease'
],
));
fileSystem.file('android/gradlew').createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.file('android/build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
await expectLater(() async {
await builder.buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
androidGradleDaemon: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
}, throwsToolExit());
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => Artifacts.test(),
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[]),
});
testUsingContext('build aar uses selected local engine,the engine abi is arm', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: TargetPlatform.android_arm,
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_arm'));
fileSystem.file('out/android_arm/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_arm/armeabi_v7a_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm/armeabi_v7a_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm/armeabi_v7a_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.directory('.android/gradle')
.createSync(recursive: true);
fileSystem.directory('.android/gradle/wrapper')
.createSync(recursive: true);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
when(fileSystemUtils.copyDirectorySync(any, any)).thenReturn(null);
await builder.buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '2.0',
);
final List<String> actualGradlewCall = verify(
mockProcessManager.run(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/.android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
expect(actualGradlewCall, contains('-PbuildNumber=2.0'));
// Verify the local engine repo is copied into the generated Maven repo.
final List<dynamic> copyDirectoryArguments = verify(
fileSystemUtils.copyDirectorySync(captureAny, captureAny)
).captured;
expect(copyDirectoryArguments.length, 2);
expect((copyDirectoryArguments.first as Directory).path, '/.tmp_rand0/flutter_tool_local_engine_repo.rand0');
expect((copyDirectoryArguments.last as Directory).path, 'build/outputs/repo');
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
FileSystemUtils: () => fileSystemUtils,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build aar uses selected local engine,the engine abi is arm64', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_arm64'));
fileSystem.file('out/android_arm64/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_arm64/arm64_v8a_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm64/arm64_v8a_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm64/arm64_v8a_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.directory('.android/gradle')
.createSync(recursive: true);
fileSystem.directory('.android/gradle/wrapper')
.createSync(recursive: true);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
when(fileSystemUtils.copyDirectorySync(any, any)).thenReturn(null);
await builder.buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '2.0',
);
final List<String> actualGradlewCall = verify(
mockProcessManager.run(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/.android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm64'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
expect(actualGradlewCall, contains('-PbuildNumber=2.0'));
// Verify the local engine repo is copied into the generated Maven repo.
final List<dynamic> copyDirectoryArguments = verify(
fileSystemUtils.copyDirectorySync(captureAny, captureAny)
).captured;
expect(copyDirectoryArguments.length, 2);
expect((copyDirectoryArguments.first as Directory).path, '/.tmp_rand0/flutter_tool_local_engine_repo.rand0');
expect((copyDirectoryArguments.last as Directory).path, 'build/outputs/repo');
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
FileSystemUtils: () => fileSystemUtils,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build aar uses selected local engine,the engine abi is x86', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_x86'));
fileSystem.file('out/android_x86/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_x86/x86_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x86/x86_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x86/x86_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.directory('.android/gradle')
.createSync(recursive: true);
fileSystem.directory('.android/gradle/wrapper')
.createSync(recursive: true);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
when(fileSystemUtils.copyDirectorySync(any, any)).thenReturn(null);
await builder.buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '2.0',
);
final List<String> actualGradlewCall = verify(
mockProcessManager.run(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/.android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x86'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
expect(actualGradlewCall, contains('-PbuildNumber=2.0'));
// Verify the local engine repo is copied into the generated Maven repo.
final List<dynamic> copyDirectoryArguments = verify(
fileSystemUtils.copyDirectorySync(captureAny, captureAny)
).captured;
expect(copyDirectoryArguments.length, 2);
expect((copyDirectoryArguments.first as Directory).path, '/.tmp_rand0/flutter_tool_local_engine_repo.rand0');
expect((copyDirectoryArguments.last as Directory).path, 'build/outputs/repo');
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
FileSystemUtils: () => fileSystemUtils,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build aar uses selected local engine,the engine abi is x64', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_x64'));
fileSystem.file('out/android_x64/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_x64/x86_64_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x64/x86_64_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x64/x86_64_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.directory('.android/gradle')
.createSync(recursive: true);
fileSystem.directory('.android/gradle/wrapper')
.createSync(recursive: true);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
when(fileSystemUtils.copyDirectorySync(any, any)).thenReturn(null);
await builder.buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '2.0',
);
final List<String> actualGradlewCall = verify(
mockProcessManager.run(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/.android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x64'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
expect(actualGradlewCall, contains('-PbuildNumber=2.0'));
// Verify the local engine repo is copied into the generated Maven repo.
final List<dynamic> copyDirectoryArguments = verify(
fileSystemUtils.copyDirectorySync(captureAny, captureAny)
).captured;
expect(copyDirectoryArguments.length, 2);
expect((copyDirectoryArguments.first as Directory).path, '/.tmp_rand0/flutter_tool_local_engine_repo.rand0');
expect((copyDirectoryArguments.last as Directory).path, 'build/outputs/repo');
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
FileSystemUtils: () => fileSystemUtils,
ProcessManager: () => mockProcessManager,
});
});
}
FakePlatform fakePlatform(String name) {
return FakePlatform(
environment: <String, String>{'HOME': '/path/to/home'},
operatingSystem: name,
stdoutSupportsAnsi: false,
);
}
class MockProcessManager extends Mock implements ProcessManager {}
class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockAndroidStudio extends Mock implements AndroidStudio {}
class MockFileSystemUtils extends Mock implements FileSystemUtils {}
class MockLocalEngineArtifacts extends Mock implements LocalEngineArtifacts {}
...@@ -4,10 +4,8 @@ ...@@ -4,10 +4,8 @@
// @dart = 2.8 // @dart = 2.8
import 'package:archive/archive.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/android/android_studio.dart';
import 'package:flutter_tools/src/android/gradle.dart'; import 'package:flutter_tools/src/android/gradle.dart';
import 'package:flutter_tools/src/android/gradle_errors.dart'; import 'package:flutter_tools/src/android/gradle_errors.dart';
import 'package:flutter_tools/src/android/gradle_utils.dart'; import 'package:flutter_tools/src/android/gradle_utils.dart';
...@@ -15,7 +13,6 @@ import 'package:flutter_tools/src/artifacts.dart'; ...@@ -15,7 +13,6 @@ import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.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/io.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/terminal.dart';
...@@ -29,7 +26,6 @@ import 'package:process/process.dart'; ...@@ -29,7 +26,6 @@ import 'package:process/process.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/mocks.dart';
void main() { void main() {
Cache.flutterRoot = getFlutterRoot(); Cache.flutterRoot = getFlutterRoot();
...@@ -837,12 +833,14 @@ flutter: ...@@ -837,12 +833,14 @@ flutter:
FileSystem fs; FileSystem fs;
FakeProcessManager fakeProcessManager; FakeProcessManager fakeProcessManager;
MockAndroidSdk mockAndroidSdk; MockAndroidSdk mockAndroidSdk;
AndroidGradleBuilder builder;
setUp(() { setUp(() {
fs = MemoryFileSystem.test(); fs = MemoryFileSystem.test();
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[]); fakeProcessManager = FakeProcessManager.list(<FakeCommand>[]);
mockAndroidSdk = MockAndroidSdk(); mockAndroidSdk = MockAndroidSdk();
when(mockAndroidSdk.directory).thenReturn('irrelevant'); when(mockAndroidSdk.directory).thenReturn('irrelevant');
builder = AndroidGradleBuilder();
}); });
testUsingContext('calls gradle', () async { testUsingContext('calls gradle', () async {
...@@ -942,7 +940,7 @@ plugin2=${plugin2.path} ...@@ -942,7 +940,7 @@ plugin2=${plugin2.path}
workingDirectory: plugin2.childDirectory('android').path, workingDirectory: plugin2.childDirectory('android').path,
)); ));
await buildPluginsAsAar( await builder.buildPluginsAsAar(
FlutterProject.fromPath(androidDirectory.path), FlutterProject.fromPath(androidDirectory.path),
const AndroidBuildInfo(BuildInfo( const AndroidBuildInfo(BuildInfo(
BuildMode.release, BuildMode.release,
...@@ -995,7 +993,7 @@ plugin1=${plugin1.path} ...@@ -995,7 +993,7 @@ plugin1=${plugin1.path}
.childDirectory('repo') .childDirectory('repo')
.createSync(recursive: true); .createSync(recursive: true);
await buildPluginsAsAar( await builder.buildPluginsAsAar(
FlutterProject.fromPath(androidDirectory.path), FlutterProject.fromPath(androidDirectory.path),
const AndroidBuildInfo(BuildInfo.release), const AndroidBuildInfo(BuildInfo.release),
buildDirectory: buildDirectory, buildDirectory: buildDirectory,
...@@ -1009,1612 +1007,6 @@ plugin1=${plugin1.path} ...@@ -1009,1612 +1007,6 @@ plugin1=${plugin1.path}
}); });
}); });
group('gradle build', () {
TestUsage testUsage;
MockAndroidSdk mockAndroidSdk;
MockAndroidStudio mockAndroidStudio;
MockLocalEngineArtifacts mockArtifacts;
MockProcessManager mockProcessManager;
FakePlatform android;
FileSystem fileSystem;
FileSystemUtils fileSystemUtils;
Cache cache;
setUp(() {
testUsage = TestUsage();
fileSystem = MemoryFileSystem.test();
fileSystemUtils = MockFileSystemUtils();
mockAndroidSdk = MockAndroidSdk();
mockAndroidStudio = MockAndroidStudio();
mockArtifacts = MockLocalEngineArtifacts();
mockProcessManager = MockProcessManager();
android = fakePlatform('android');
when(mockAndroidSdk.directory).thenReturn('irrelevant');
final Directory rootDirectory = fileSystem.currentDirectory;
cache = Cache.test(
rootOverride: rootDirectory,
fileSystem: fileSystem,
);
final Directory gradleWrapperDirectory = rootDirectory
.childDirectory('bin')
.childDirectory('cache')
.childDirectory('artifacts')
.childDirectory('gradle_wrapper');
gradleWrapperDirectory.createSync(recursive: true);
gradleWrapperDirectory
.childFile('gradlew')
.writeAsStringSync('irrelevant');
gradleWrapperDirectory
.childDirectory('gradle')
.childDirectory('wrapper')
.createSync(recursive: true);
gradleWrapperDirectory
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.jar')
.writeAsStringSync('irrelevant');
});
testUsingContext('recognizes common errors - tool exit', () async {
final Process process = createMockProcess(
exitCode: 1,
stdout: 'irrelevant\nSome gradle message\nirrelevant',
);
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) => Future<Process>.value(process));
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
bool handlerCalled = false;
await expectLater(() async {
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[
GradleHandledError(
test: (String line) {
return line.contains('Some gradle message');
},
handler: ({
String line,
FlutterProject project,
bool usesAndroidX,
bool shouldBuildPluginAsAar,
}) async {
handlerCalled = true;
return GradleBuildStatus.exit;
},
eventLabel: 'random-event-label',
),
],
);
},
throwsToolExit(
message: 'Gradle task assembleRelease failed with exit code 1'
));
expect(handlerCalled, isTrue);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('recognizes common errors - retry build', () async {
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
final Process process = createMockProcess(
exitCode: 1,
stdout: 'irrelevant\nSome gradle message\nirrelevant',
);
return Future<Process>.value(process);
});
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
int testFnCalled = 0;
await expectLater(() async {
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[
GradleHandledError(
test: (String line) {
if (line.contains('Some gradle message')) {
testFnCalled++;
return true;
}
return false;
},
handler: ({
String line,
FlutterProject project,
bool usesAndroidX,
bool shouldBuildPluginAsAar,
}) async {
return GradleBuildStatus.retry;
},
eventLabel: 'random-event-label',
),
],
);
}, throwsToolExit(
message: 'Gradle task assembleRelease failed with exit code 1'
));
expect(testFnCalled, equals(2));
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('recognizes process exceptions - tool exit', () async {
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenThrow(const ProcessException('', <String>[], 'Some gradle message'));
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
bool handlerCalled = false;
await expectLater(() async {
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[
GradleHandledError(
test: (String line) {
return line.contains('Some gradle message');
},
handler: ({
String line,
FlutterProject project,
bool usesAndroidX,
bool shouldBuildPluginAsAar,
}) async {
handlerCalled = true;
return GradleBuildStatus.exit;
},
eventLabel: 'random-event-label',
),
],
);
},
throwsToolExit(
message: 'Gradle task assembleRelease failed with exit code 1'
));
expect(handlerCalled, isTrue);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('rethrows unrecognized ProcessException', () async {
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenThrow(const ProcessException('', <String>[], 'Unrecognized'));
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
await expectLater(() async {
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
},
throwsA(isA<ProcessException>()));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext('logs success event after a successful retry', () async {
int testFnCalled = 0;
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
Process process;
if (testFnCalled == 0) {
process = createMockProcess(
exitCode: 1,
stdout: 'irrelevant\nSome gradle message\nirrelevant',
);
} else {
process = createMockProcess(
exitCode: 0,
stdout: 'irrelevant',
);
}
testFnCalled++;
return Future<Process>.value(process);
});
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
fileSystem.directory('build')
.childDirectory('app')
.childDirectory('outputs')
.childDirectory('flutter-apk')
.childFile('app-release.apk')
.createSync(recursive: true);
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[
GradleHandledError(
test: (String line) {
return line.contains('Some gradle message');
},
handler: ({
String line,
FlutterProject project,
bool usesAndroidX,
bool shouldBuildPluginAsAar,
}) async {
return GradleBuildStatus.retry;
},
eventLabel: 'random-event-label',
),
],
);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-success',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
FileSystem: () => fileSystem,
Platform: () => android,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('performs code size analysis and sends analytics', () async {
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
return Future<Process>.value(createMockProcess(
exitCode: 0,
stdout: 'irrelevant',
));
});
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
final Archive archive = Archive()
..addFile(ArchiveFile('AndroidManifest.xml', 100, List<int>.filled(100, 0)))
..addFile(ArchiveFile('META-INF/CERT.RSA', 10, List<int>.filled(10, 0)))
..addFile(ArchiveFile('META-INF/CERT.SF', 10, List<int>.filled(10, 0)))
..addFile(ArchiveFile('lib/arm64-v8a/libapp.so', 50, List<int>.filled(50, 0)))
..addFile(ArchiveFile('lib/arm64-v8a/libflutter.so', 50, List<int>.filled(50, 0)));
fileSystem.directory('build')
.childDirectory('app')
.childDirectory('outputs')
.childDirectory('flutter-apk')
.childFile('app-release.apk')
..createSync(recursive: true)
..writeAsBytesSync(ZipEncoder().encode(archive));
fileSystem.file('foo/snapshot.arm64-v8a.json')
..createSync(recursive: true)
..writeAsStringSync(r'''
[
{
"l": "dart:_internal",
"c": "SubListIterable",
"n": "[Optimized] skip",
"s": 2400
}
]''');
fileSystem.file('foo/trace.arm64-v8a.json')
..createSync(recursive: true)
..writeAsStringSync('{}');
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
codeSizeDirectory: 'foo',
),
targetArchs: <AndroidArch>[AndroidArch.arm64_v8a],
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[],
);
expect(testUsage.events, contains(
const TestUsageEvent(
'code-size-analysis',
'apk',
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
FileSystem: () => fileSystem,
Platform: () => android,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('recognizes common errors - retry build with AAR plugins', () async {
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
final Process process = createMockProcess(
exitCode: 1,
stdout: 'irrelevant\nSome gradle message\nirrelevant',
);
return Future<Process>.value(process);
});
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
int testFnCalled = 0;
bool builtPluginAsAar = false;
await expectLater(() async {
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: <GradleHandledError>[
GradleHandledError(
test: (String line) {
if (line.contains('Some gradle message')) {
testFnCalled++;
return true;
}
return false;
},
handler: ({
String line,
FlutterProject project,
bool usesAndroidX,
bool shouldBuildPluginAsAar,
}) async {
if (testFnCalled == 2) {
builtPluginAsAar = shouldBuildPluginAsAar;
}
return GradleBuildStatus.retryWithAarPlugins;
},
eventLabel: 'random-event-label',
),
],
);
}, throwsToolExit(
message: 'Gradle task assembleRelease failed with exit code 1'
));
expect(testFnCalled, equals(2));
expect(builtPluginAsAar, isTrue);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => testUsage,
});
testUsingContext('indicates that an APK has been built successfully', () async {
fileSystem.directory('android')
.childFile('build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
fileSystem.directory('build')
.childDirectory('app')
.childDirectory('outputs')
.childDirectory('flutter-apk')
.childFile('app-release.apk')
.createSync(recursive: true);
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
expect(
testLogger.statusText,
contains('Built build/app/outputs/flutter-apk/app-release.apk (0.0MB)'),
);
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
FileSystem: () => fileSystem,
Platform: () => android,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext("doesn't indicate how to consume an AAR when printHowToConsumeAaar is false", () async {
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
await buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '1.0',
);
expect(
testLogger.statusText,
contains('Built build/outputs/repo'),
);
expect(
testLogger.statusText.contains('Consuming the Module'),
isFalse,
);
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext('gradle exit code is properly passed on', () async {
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 108, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
await expectLater(() async =>
await buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '1.0',
)
, throwsToolExit(exitCode: 108, message: 'Gradle task assembleAarRelease failed with exit code 108.'));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext('build apk uses selected local engine,the engine abi is arm', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: TargetPlatform.android_arm,
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_arm'));
fileSystem.file('out/android_arm/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_arm/armeabi_v7a_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm/armeabi_v7a_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm/armeabi_v7a_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('android/gradlew').createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.file('android/build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
return Future<Process>.value(
createMockProcess(
exitCode: 1,
)
);
});
await expectLater(() async {
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
}, throwsToolExit());
final List<String> actualGradlewCall = verify(
mockProcessManager.start(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build apk uses selected local engine,the engine abi is arm64', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_arm64'));
fileSystem.file('out/android_arm64/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_arm64/arm64_v8a_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm64/arm64_v8a_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm64/arm64_v8a_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('android/gradlew').createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.file('android/build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
return Future<Process>.value(
createMockProcess(
exitCode: 1,
)
);
});
await expectLater(() async {
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
}, throwsToolExit());
final List<String> actualGradlewCall = verify(
mockProcessManager.start(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm64'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build apk uses selected local engine,the engine abi is x86', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_x86'));
fileSystem.file('out/android_x86/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_x86/x86_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x86/x86_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x86/x86_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('android/gradlew').createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.file('android/build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
return Future<Process>.value(
createMockProcess(
exitCode: 1,
)
);
});
await expectLater(() async {
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
}, throwsToolExit());
final List<String> actualGradlewCall = verify(
mockProcessManager.start(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x86'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build apk uses selected local engine,the engine abi is x64', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_x64'));
fileSystem.file('out/android_x64/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_x64/x86_64_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x64/x86_64_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x64/x86_64_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('android/gradlew').createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.file('android/build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
when(mockProcessManager.start(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) {
return Future<Process>.value(
createMockProcess(
exitCode: 1,
)
);
});
await expectLater(() async {
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
}, throwsToolExit());
final List<String> actualGradlewCall = verify(
mockProcessManager.start(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x64'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
});
testUsingContext('honors --no-android-gradle-daemon setting', () async {
(globals.processManager as FakeProcessManager).addCommand(
const FakeCommand(command: <String>[
'/android/gradlew',
'-q',
'--no-daemon',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
'assembleRelease'
],
));
fileSystem.file('android/gradlew').createSync(recursive: true);
fileSystem.directory('android')
.childFile('gradle.properties')
.createSync(recursive: true);
fileSystem.file('android/build.gradle')
.createSync(recursive: true);
fileSystem.directory('android')
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
await expectLater(() async {
await buildGradleApp(
project: FlutterProject.current(),
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(
BuildMode.release,
null,
treeShakeIcons: false,
androidGradleDaemon: false,
),
),
target: 'lib/main.dart',
isBuildingBundle: false,
localGradleErrors: const <GradleHandledError>[],
);
}, throwsToolExit());
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => Artifacts.test(),
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[]),
});
testUsingContext('build aar uses selected local engine,the engine abi is arm', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: TargetPlatform.android_arm,
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_arm'));
fileSystem.file('out/android_arm/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_arm/armeabi_v7a_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm/armeabi_v7a_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm/armeabi_v7a_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.directory('.android/gradle')
.createSync(recursive: true);
fileSystem.directory('.android/gradle/wrapper')
.createSync(recursive: true);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
when(fileSystemUtils.copyDirectorySync(any, any)).thenReturn(null);
await buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '2.0',
);
final List<String> actualGradlewCall = verify(
mockProcessManager.run(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/.android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
expect(actualGradlewCall, contains('-PbuildNumber=2.0'));
// Verify the local engine repo is copied into the generated Maven repo.
final List<dynamic> copyDirectoryArguments = verify(
fileSystemUtils.copyDirectorySync(captureAny, captureAny)
).captured;
expect(copyDirectoryArguments.length, 2);
expect((copyDirectoryArguments.first as Directory).path, '/.tmp_rand0/flutter_tool_local_engine_repo.rand0');
expect((copyDirectoryArguments.last as Directory).path, 'build/outputs/repo');
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
FileSystemUtils: () => fileSystemUtils,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build aar uses selected local engine,the engine abi is arm64', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_arm64'));
fileSystem.file('out/android_arm64/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_arm64/arm64_v8a_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm64/arm64_v8a_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm64/arm64_v8a_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_arm64/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.directory('.android/gradle')
.createSync(recursive: true);
fileSystem.directory('.android/gradle/wrapper')
.createSync(recursive: true);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
when(fileSystemUtils.copyDirectorySync(any, any)).thenReturn(null);
await buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '2.0',
);
final List<String> actualGradlewCall = verify(
mockProcessManager.run(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/.android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_arm64'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
expect(actualGradlewCall, contains('-PbuildNumber=2.0'));
// Verify the local engine repo is copied into the generated Maven repo.
final List<dynamic> copyDirectoryArguments = verify(
fileSystemUtils.copyDirectorySync(captureAny, captureAny)
).captured;
expect(copyDirectoryArguments.length, 2);
expect((copyDirectoryArguments.first as Directory).path, '/.tmp_rand0/flutter_tool_local_engine_repo.rand0');
expect((copyDirectoryArguments.last as Directory).path, 'build/outputs/repo');
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
FileSystemUtils: () => fileSystemUtils,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build aar uses selected local engine,the engine abi is x86', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_x86'));
fileSystem.file('out/android_x86/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_x86/x86_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x86/x86_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x86/x86_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x86/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.directory('.android/gradle')
.createSync(recursive: true);
fileSystem.directory('.android/gradle/wrapper')
.createSync(recursive: true);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
when(fileSystemUtils.copyDirectorySync(any, any)).thenReturn(null);
await buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '2.0',
);
final List<String> actualGradlewCall = verify(
mockProcessManager.run(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/.android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x86'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
expect(actualGradlewCall, contains('-PbuildNumber=2.0'));
// Verify the local engine repo is copied into the generated Maven repo.
final List<dynamic> copyDirectoryArguments = verify(
fileSystemUtils.copyDirectorySync(captureAny, captureAny)
).captured;
expect(copyDirectoryArguments.length, 2);
expect((copyDirectoryArguments.first as Directory).path, '/.tmp_rand0/flutter_tool_local_engine_repo.rand0');
expect((copyDirectoryArguments.last as Directory).path, 'build/outputs/repo');
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
FileSystemUtils: () => fileSystemUtils,
ProcessManager: () => mockProcessManager,
});
testUsingContext(
'build aar uses selected local engine,the engine abi is x64', () async {
when(mockArtifacts.getArtifactPath(
Artifact.flutterFramework,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
environmentType: anyNamed('environmentType'),
)).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fileSystem.path.join('out', 'android_x64'));
fileSystem.file('out/android_x64/flutter_embedding_release.pom')
..createSync(recursive: true)
..writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<project>
<version>1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b</version>
<dependencies>
</dependencies>
</project>
''');
fileSystem.file('out/android_x64/x86_64_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x64/x86_64_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x64/x86_64_release.maven-metadata.xml').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.jar').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.pom').createSync(recursive: true);
fileSystem.file('out/android_x64/flutter_embedding_release.maven-metadata.xml').createSync(recursive: true);
final File manifestFile = fileSystem.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fileSystem.directory('.android/gradle')
.createSync(recursive: true);
fileSystem.directory('.android/gradle/wrapper')
.createSync(recursive: true);
fileSystem.file('.android/gradlew').createSync(recursive: true);
fileSystem.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fileSystem.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fileSystem.directory('build/outputs/repo').createSync(recursive: true);
when(fileSystemUtils.copyDirectorySync(any, any)).thenReturn(null);
await buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(
BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
project: FlutterProject.current(),
outputDirectory: fileSystem.directory('build/'),
target: '',
buildNumber: '2.0',
);
final List<String> actualGradlewCall = verify(
mockProcessManager.run(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
),
).captured.last as List<String>;
expect(actualGradlewCall, contains('/.android/gradlew'));
expect(actualGradlewCall, contains('-Plocal-engine-out=out/android_x64'));
expect(actualGradlewCall, contains('-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0'));
expect(actualGradlewCall, contains('-Plocal-engine-build-mode=release'));
expect(actualGradlewCall, contains('-PbuildNumber=2.0'));
// Verify the local engine repo is copied into the generated Maven repo.
final List<dynamic> copyDirectoryArguments = verify(
fileSystemUtils.copyDirectorySync(captureAny, captureAny)
).captured;
expect(copyDirectoryArguments.length, 2);
expect((copyDirectoryArguments.first as Directory).path, '/.tmp_rand0/flutter_tool_local_engine_repo.rand0');
expect((copyDirectoryArguments.last as Directory).path, 'build/outputs/repo');
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Artifacts: () => mockArtifacts,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
FileSystemUtils: () => fileSystemUtils,
ProcessManager: () => mockProcessManager,
});
});
group('printHowToConsumeAar', () { group('printHowToConsumeAar', () {
BufferLogger logger; BufferLogger logger;
FileSystem fileSystem; FileSystem fileSystem;
...@@ -2854,8 +1246,6 @@ class FakeGradleUtils extends GradleUtils { ...@@ -2854,8 +1246,6 @@ class FakeGradleUtils extends GradleUtils {
class MockAndroidSdk extends Mock implements AndroidSdk {} class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockAndroidProject extends Mock implements AndroidProject {} class MockAndroidProject extends Mock implements AndroidProject {}
class MockAndroidStudio extends Mock implements AndroidStudio {}
class MockFileSystemUtils extends Mock implements FileSystemUtils {}
class MockFlutterProject extends Mock implements FlutterProject {} class MockFlutterProject extends Mock implements FlutterProject {}
class MockLocalEngineArtifacts extends Mock implements LocalEngineArtifacts {} class MockLocalEngineArtifacts extends Mock implements LocalEngineArtifacts {}
class MockProcessManager extends Mock implements ProcessManager {} class MockProcessManager extends Mock implements ProcessManager {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment