blob: d074e28bc8bbe63bb4846c677528e4ccada9682b [file] [log] [blame]
// 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 '../android/android_builder.dart';
import '../android/build_validation.dart';
import '../android/deferred_components_prebuild_validator.dart';
import '../android/gradle_utils.dart';
import '../base/deferred_component.dart';
import '../base/file_system.dart';
import '../build_info.dart';
import '../cache.dart';
import '../globals_null_migrated.dart' as globals;
import '../project.dart';
import '../reporting/reporting.dart';
import '../runner/flutter_command.dart' show FlutterCommandResult;
import 'build.dart';
class BuildAppBundleCommand extends BuildSubCommand {
BuildAppBundleCommand({bool verboseHelp = false}) {
addTreeShakeIconsFlag();
usesTargetOption();
addBuildModeFlags(verboseHelp: verboseHelp);
usesFlavorOption();
usesPubOption();
usesBuildNumberOption();
usesBuildNameOption();
addShrinkingFlag(verboseHelp: verboseHelp);
addSplitDebugInfoOption();
addDartObfuscationOption();
usesDartDefineOption();
usesExtraDartFlagOptions(verboseHelp: verboseHelp);
addBundleSkSLPathOption(hide: !verboseHelp);
addBuildPerformanceFile(hide: !verboseHelp);
usesTrackWidgetCreation(verboseHelp: verboseHelp);
addNullSafetyModeOptions(hide: !verboseHelp);
addEnableExperimentation(hide: !verboseHelp);
usesAnalyzeSizeFlag();
addAndroidSpecificBuildOptions(hide: !verboseHelp);
argParser.addMultiOption('target-platform',
splitCommas: true,
defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'],
allowed: <String>['android-arm', 'android-arm64', 'android-x64'],
help: 'The target platform for which the app is compiled.',
);
argParser.addFlag('deferred-components',
negatable: true,
defaultsTo: true,
help: 'Setting to false disables building with deferred components. All deferred code '
'will be compiled into the base app, and assets act as if they were defined under'
' the regular assets section in pubspec.yaml. This flag has no effect on '
'non-deferred components apps.',
);
argParser.addFlag('validate-deferred-components',
negatable: true,
defaultsTo: true,
help: 'When enabled, deferred component apps will fail to build if setup problems are '
'detected that would prevent deferred components from functioning properly. The '
'tooling also provides guidance on how to set up the project files to pass this '
'verification. Disabling setup verification will always attempt to fully build '
'the app regardless of any problems detected. Builds that are part of CI testing '
'and advanced users with custom deferred components implementations should disable '
'setup verification. This flag has no effect on non-deferred components apps.',
);
}
@override
final String name = 'appbundle';
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
DevelopmentArtifact.androidGenSnapshot,
};
@override
final String description =
'Build an Android App Bundle file from your app.\n\n'
"This command can build debug and release versions of an app bundle for your application. 'debug' builds support "
"debugging and a quick development cycle. 'release' builds don't support debugging and are "
'suitable for deploying to app stores. \n app bundle improves your app size';
@override
Future<Map<CustomDimensions, String>> get usageValues async {
final Map<CustomDimensions, String> usage = <CustomDimensions, String>{};
usage[CustomDimensions.commandBuildAppBundleTargetPlatform] =
stringsArg('target-platform').join(',');
if (boolArg('release')) {
usage[CustomDimensions.commandBuildAppBundleBuildMode] = 'release';
} else if (boolArg('debug')) {
usage[CustomDimensions.commandBuildAppBundleBuildMode] = 'debug';
} else if (boolArg('profile')) {
usage[CustomDimensions.commandBuildAppBundleBuildMode] = 'profile';
} else {
// The build defaults to release.
usage[CustomDimensions.commandBuildAppBundleBuildMode] = 'release';
}
return usage;
}
@override
Future<FlutterCommandResult> runCommand() async {
if (globals.androidSdk == null) {
exitWithNoSdkMessage();
}
final AndroidBuildInfo androidBuildInfo = AndroidBuildInfo(await getBuildInfo(),
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
);
// Do all setup verification that doesn't involve loading units. Checks that
// require generated loading units are done after gen_snapshot in assemble.
if (FlutterProject.current().manifest.deferredComponents != null && boolArg('deferred-components') && boolArg('validate-deferred-components') && !boolArg('debug')) {
final DeferredComponentsPrebuildValidator validator = DeferredComponentsPrebuildValidator(
FlutterProject.current().directory,
globals.logger,
globals.platform,
title: 'Deferred components prebuild validation',
exitOnFail: true,
);
validator.clearOutputDir();
await validator.checkAndroidDynamicFeature(FlutterProject.current().manifest.deferredComponents);
validator.checkAndroidResourcesStrings(FlutterProject.current().manifest.deferredComponents);
validator.handleResults();
// Delete intermediates libs dir for components to resolve mismatching
// abis supported by base and dynamic feature modules.
for (final DeferredComponent component in FlutterProject.current().manifest.deferredComponents) {
final Directory deferredLibsIntermediate = FlutterProject.current().directory
.childDirectory('build')
.childDirectory(component.name)
.childDirectory('intermediates')
.childDirectory('flutter')
.childDirectory(androidBuildInfo.buildInfo.mode.name)
.childDirectory('deferred_libs');
if (deferredLibsIntermediate.existsSync()) {
deferredLibsIntermediate.deleteSync(recursive: true);
}
}
}
validateBuild(androidBuildInfo);
displayNullSafetyMode(androidBuildInfo.buildInfo);
await androidBuilder.buildAab(
project: FlutterProject.current(),
target: targetFile,
androidBuildInfo: androidBuildInfo,
validateDeferredComponents: boolArg('validate-deferred-components'),
deferredComponentsEnabled: boolArg('deferred-components') && !boolArg('debug'),
);
return FlutterCommandResult.success();
}
}