show build progress; print app sizes (#4263)
* show build progress; print app sizes * add todo * review comments * remove unused import
This commit is contained in:
parent
26a4d7bbad
commit
7c47837c27
@ -164,6 +164,8 @@ class RunResult {
|
||||
final ProcessResult processResult;
|
||||
|
||||
int get exitCode => processResult.exitCode;
|
||||
String get stdout => processResult.stdout;
|
||||
String get stderr => processResult.stderr;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
|
@ -71,6 +71,11 @@ String toPrettyJson(Object jsonable) {
|
||||
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.
|
||||
|
@ -7,6 +7,7 @@ import 'dart:io';
|
||||
|
||||
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 @@ class BuildAotCommand extends FlutterCommand {
|
||||
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 @@ String _getSdkExtensionPath(String packagesPath, String package) {
|
||||
|
||||
/// 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(
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ String _buildAotSnapshot(
|
||||
|
||||
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.
|
||||
|
@ -11,6 +11,7 @@ import 'package:path/path.dart' as path;
|
||||
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 @@ int _buildApk(
|
||||
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 @@ Future<int> buildAndroid(
|
||||
}
|
||||
|
||||
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 @@ Future<int> buildAndroid(
|
||||
|
||||
// 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 @@ Future<int> buildAndroid(
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 @@ class BuildIOSCommand extends FlutterCommand {
|
||||
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;
|
||||
}
|
||||
|
@ -180,8 +180,8 @@ class IOSDevice extends Device {
|
||||
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();
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ bool _xcodeVersionCheckValid(int major, int minor) {
|
||||
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 @@ Future<bool> buildIOSXcodeProject(ApplicationPackage app, BuildMode mode,
|
||||
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 @@ Future<bool> buildIOSXcodeProject(ApplicationPackage app, BuildMode mode,
|
||||
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+)\..*');
|
||||
|
@ -548,8 +548,8 @@ class IOSSimulator extends Device {
|
||||
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user