show build progress; print app sizes (#4263)
* show build progress; print app sizes
* add todo
* review comments
* remove unused import
diff --git a/packages/flutter_tools/lib/src/base/process.dart b/packages/flutter_tools/lib/src/base/process.dart
index d4287a1..c0c672f 100644
--- a/packages/flutter_tools/lib/src/base/process.dart
+++ b/packages/flutter_tools/lib/src/base/process.dart
@@ -164,6 +164,8 @@
final ProcessResult processResult;
int get exitCode => processResult.exitCode;
+ String get stdout => processResult.stdout;
+ String get stderr => processResult.stderr;
@override
String toString() {
diff --git a/packages/flutter_tools/lib/src/base/utils.dart b/packages/flutter_tools/lib/src/base/utils.dart
index 052e671..5fb325f 100644
--- a/packages/flutter_tools/lib/src/base/utils.dart
+++ b/packages/flutter_tools/lib/src/base/utils.dart
@@ -71,6 +71,11 @@
return new JsonEncoder.withIndent(' ').convert(jsonable) + '\n';
}
+/// Return a String - with units - for the size in MB of the given number of bytes.
+String getSizeAsMB(int bytesLength) {
+ return '${(bytesLength / (1024 * 1024)).toStringAsFixed(1)}MB';
+}
+
/// A class to maintain a list of items, fire events when items are added or
/// removed, and calculate a diff of changes when a new list of items is
/// available.
diff --git a/packages/flutter_tools/lib/src/commands/build_aot.dart b/packages/flutter_tools/lib/src/commands/build_aot.dart
index 1813b63..53c78df 100644
--- a/packages/flutter_tools/lib/src/commands/build_aot.dart
+++ b/packages/flutter_tools/lib/src/commands/build_aot.dart
@@ -7,6 +7,7 @@
import 'package:path/path.dart' as path;
+import '../base/logger.dart';
import '../base/process.dart';
import '../base/utils.dart';
import '../build_info.dart';
@@ -50,17 +51,22 @@
printError('Unknown platform: $targetPlatform');
return 1;
}
- String outputPath = buildAotSnapshot(
+
+ String typeName = path.basename(tools.getEngineArtifactsDirectory(platform, getBuildMode()).path);
+ Status status = logger.startProgress('Building AOT snapshot in ${getModeName(getBuildMode())} mode ($typeName)...');
+ String outputPath = await buildAotSnapshot(
findMainDartFile(argResults['target']),
platform,
getBuildMode(),
outputPath: argResults['output-dir'],
interpreter: argResults['interpreter']
);
+ status.stop(showElapsedTime: true);
+
if (outputPath == null)
return 1;
- printStatus('Built $outputPath.');
+ printStatus('Built to $outputPath${Platform.pathSeparator}.');
return 0;
}
}
@@ -72,13 +78,13 @@
/// Build an AOT snapshot. Return `null` (and log to `printError`) if the method
/// fails.
-String buildAotSnapshot(
+Future<String> buildAotSnapshot(
String mainPath,
TargetPlatform platform,
BuildMode buildMode, {
String outputPath: _kDefaultAotOutputDir,
bool interpreter: false
-}) {
+}) async {
try {
return _buildAotSnapshot(
mainPath,
@@ -94,13 +100,13 @@
}
}
-String _buildAotSnapshot(
+Future<String> _buildAotSnapshot(
String mainPath,
TargetPlatform platform,
BuildMode buildMode, {
String outputPath: _kDefaultAotOutputDir,
bool interpreter: false
-}) {
+}) async {
if (!isAotBuildMode(buildMode)) {
printError('${toTitleCase(getModeName(buildMode))} mode does not support AOT compilation.');
return null;
@@ -253,10 +259,11 @@
genSnapshotCmd.add(mainPath);
- String typeName = path.basename(tools.getEngineArtifactsDirectory(platform, buildMode).path);
- printStatus('Building snapshot in ${getModeName(buildMode)} mode ($typeName)...');
-
- runCheckedSync(genSnapshotCmd, truncateCommand: true);
+ RunResult results = await runAsync(genSnapshotCmd);
+ if (results.exitCode != 0) {
+ printStatus(results.toString());
+ return null;
+ }
// On iOS, we use Xcode to compile the snapshot into a dynamic library that the
// end-developer can link into their app.
diff --git a/packages/flutter_tools/lib/src/commands/build_apk.dart b/packages/flutter_tools/lib/src/commands/build_apk.dart
index 6211482..38f576f 100644
--- a/packages/flutter_tools/lib/src/commands/build_apk.dart
+++ b/packages/flutter_tools/lib/src/commands/build_apk.dart
@@ -11,6 +11,7 @@
import '../android/android_sdk.dart';
import '../base/file_system.dart' show ensureDirectoryExists;
import '../base/os.dart';
+import '../base/logger.dart';
import '../base/process.dart';
import '../base/utils.dart';
import '../build_info.dart';
@@ -347,9 +348,6 @@
File apkShaFile = new File('$outputFile.sha1');
apkShaFile.writeAsStringSync(calculateSha(finalApk));
- double size = finalApk.lengthSync() / (1024 * 1024);
- printStatus('Built ${finalApk.path} (${size.toStringAsFixed(1)}MB).');
-
return 0;
} finally {
tempDir.deleteSync(recursive: true);
@@ -492,7 +490,7 @@
}
String typeName = path.basename(tools.getEngineArtifactsDirectory(platform, buildMode).path);
- printStatus('Building APK in ${getModeName(buildMode)} mode ($typeName)...');
+ Status status = logger.startProgress('Building APK in ${getModeName(buildMode)} mode ($typeName)...');
if (flxPath != null && flxPath.isNotEmpty) {
if (!FileSystemEntity.isFileSync(flxPath)) {
@@ -513,7 +511,7 @@
// Build an AOT snapshot if needed.
if (isAotBuildMode(buildMode) && aotPath == null) {
- aotPath = buildAotSnapshot(findMainDartFile(target), platform, buildMode);
+ aotPath = await buildAotSnapshot(findMainDartFile(target), platform, buildMode);
if (aotPath == null) {
printError('Failed to build AOT snapshot');
return 1;
@@ -540,13 +538,19 @@
}
int result = _buildApk(platform, buildMode, components, flxPath, keystore, outputFile);
+ status.stop(showElapsedTime: true);
+
if (result == 0) {
+ File apkFile = new File(outputFile);
+ printStatus('Built $outputFile (${getSizeAsMB(apkFile.lengthSync())}).');
+
_writeBuildMetaEntry(
path.dirname(outputFile),
'targetBuildType',
_getTargetBuildTypeToken(platform, buildMode, new File(outputFile))
);
}
+
return result;
}
diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart
index 0b95ff6..3385b75 100644
--- a/packages/flutter_tools/lib/src/commands/build_ios.dart
+++ b/packages/flutter_tools/lib/src/commands/build_ios.dart
@@ -4,7 +4,10 @@
import 'dart:async';
+import 'package:path/path.dart' as path;
+
import '../application_package.dart';
+import '../base/logger.dart';
import '../build_info.dart';
import '../globals.dart';
import '../ios/mac.dart';
@@ -42,24 +45,26 @@
bool shouldCodesign = argResults['codesign'];
if (!forSimulator && !shouldCodesign) {
- printStatus('Warning: Building for device with codesigning disabled.');
- printStatus('You will have to manually codesign before deploying to device.');
+ printStatus('Warning: Building for device with codesigning disabled. You will '
+ 'have to manually codesign before deploying to device.');
}
String logTarget = forSimulator ? 'simulator' : 'device';
- printStatus('Building $app for $logTarget...');
-
- bool result = await buildIOSXcodeProject(app, getBuildMode(),
+ String typeName = path.basename(tools.getEngineArtifactsDirectory(TargetPlatform.ios, getBuildMode()).path);
+ Status status = logger.startProgress('Building $app for $logTarget ($typeName)...');
+ XcodeBuildResult result = await buildXcodeProject(app, getBuildMode(),
buildForDevice: !forSimulator,
codesign: shouldCodesign);
+ status.stop(showElapsedTime: true);
- if (!result) {
+ if (!result.success) {
printError('Encountered error while building for $logTarget.');
return 1;
}
- printStatus('Built in ios/.generated.');
+ if (result.output != null)
+ printStatus('Built ${result.output}.');
return 0;
}
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index c86cf80..4a1e72d 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -180,8 +180,8 @@
printTrace('Building ${app.name} for $id');
// Step 1: Install the precompiled/DBC application if necessary.
- bool buildResult = await buildIOSXcodeProject(app, mode, buildForDevice: true);
- if (!buildResult) {
+ XcodeBuildResult buildResult = await buildXcodeProject(app, mode, buildForDevice: true);
+ if (!buildResult.success) {
printError('Could not build the precompiled application for the device.');
return new LaunchResult.failed();
}
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index d6db90d..03ca717 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -97,7 +97,7 @@
return false;
}
-Future<bool> buildIOSXcodeProject(ApplicationPackage app, BuildMode mode,
+Future<XcodeBuildResult> buildXcodeProject(ApplicationPackage app, BuildMode mode,
{ bool buildForDevice, bool codesign: true }) async {
String flutterProjectPath = Directory.current.path;
@@ -105,17 +105,17 @@
printTrace('Initializing the Xcode project.');
if ((await setupXcodeProjectHarness(flutterProjectPath, mode)) != 0) {
printError('Could not initialize the Xcode project.');
- return false;
+ return new XcodeBuildResult(false);
}
} else {
updateXcodeLocalProperties(flutterProjectPath);
}
if (!_validateEngineRevision(app))
- return false;
+ return new XcodeBuildResult(false);
if (!_checkXcodeVersion())
- return false;
+ return new XcodeBuildResult(false);
// Before the build, all service definitions must be updated and the dylibs
// copied over to a location that is suitable for Xcodebuild to find them.
@@ -148,20 +148,30 @@
commands.addAll(<String>['-sdk', 'iphonesimulator', '-arch', 'x86_64']);
}
- printTrace(commands.join(' '));
-
- ProcessResult result = Process.runSync(
- commands.first, commands.sublist(1), workingDirectory: app.rootPath
- );
+ RunResult result = await runAsync(commands, workingDirectory: app.rootPath);
if (result.exitCode != 0) {
if (result.stderr.isNotEmpty)
printStatus(result.stderr);
if (result.stdout.isNotEmpty)
printStatus(result.stdout);
+ return new XcodeBuildResult(false);
+ } else {
+ // Look for 'clean build/Release-iphoneos/Runner.app'.
+ RegExp regexp = new RegExp(r' clean (\S*\.app)$', multiLine: true);
+ Match match = regexp.firstMatch(result.stdout);
+ String outputDir;
+ if (match != null)
+ outputDir = path.join(app.rootPath, match.group(1));
+ return new XcodeBuildResult(true, outputDir);
}
+}
- return result.exitCode == 0;
+class XcodeBuildResult {
+ XcodeBuildResult(this.success, [this.output]);
+
+ final bool success;
+ final String output;
}
final RegExp _xcodeVersionRegExp = new RegExp(r'Xcode (\d+)\..*');
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index 58ae15b..6409396 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -548,8 +548,8 @@
Future<bool> _buildAndInstallApplicationBundle(ApplicationPackage app) async {
// Step 1: Build the Xcode project.
// The build mode for the simulator is always debug.
- bool buildResult = await buildIOSXcodeProject(app, BuildMode.debug, buildForDevice: false);
- if (!buildResult) {
+ XcodeBuildResult buildResult = await buildXcodeProject(app, BuildMode.debug, buildForDevice: false);
+ if (!buildResult.success) {
printError('Could not build the application for the simulator.');
return false;
}