[flutter_tools] describe current null safety build mode (#73426)

This commit is contained in:
Jonah Williams 2021-01-07 10:26:51 -08:00 committed by GitHub
parent 5a4df0ad2c
commit ed66037f51
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 89 additions and 25 deletions

View file

@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:meta/meta.dart';
import '../build_info.dart';
import '../commands/build_linux.dart';
import '../commands/build_macos.dart';
import '../commands/build_windows.dart';
@ -52,4 +55,25 @@ abstract class BuildSubCommand extends FlutterCommand {
@override
bool get reportNullSafety => true;
/// Display a message describing the current null safety runtime mode
/// that was selected.
///
/// This is similar to the run message in run_hot.dart
@protected
void displayNullSafetyMode(BuildInfo buildInfo) {
globals.printStatus('');
if (buildInfo.nullSafetyMode == NullSafetyMode.sound) {
globals.printStatus('💪 Building with sound null safety 💪', emphasis: true);
} else {
globals.printStatus(
'Building with unsound null safety',
emphasis: true,
);
globals.printStatus(
'For more information see https://dart.dev/null-safety/unsound-null-safety',
);
}
globals.printStatus('');
}
}

View file

@ -126,6 +126,7 @@ class BuildAarCommand extends BuildSubCommand {
throwToolExit('Please specify a build mode and try again.');
}
displayNullSafetyMode(androidBuildInfo.first.buildInfo);
await androidBuilder.buildAar(
project: _getProject(),
target: '', // Not needed because this command only builds Android's code.

View file

@ -5,7 +5,6 @@
import '../android/android_builder.dart';
import '../android/build_validation.dart';
import '../android/gradle_utils.dart';
import '../base/terminal.dart';
import '../build_info.dart';
import '../cache.dart';
import '../globals.dart' as globals;
@ -61,7 +60,10 @@ class BuildApkCommand extends BuildSubCommand {
final String description = 'Build an Android APK file from your app.\n\n'
"This command can build debug and release versions of 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.';
'suitable for deploying to app stores. If you are deploying the app to the Play Store, '
'it\'s recommended to use app bundles or split the APK to reduce the APK size. Learn more at:\n\n'
' * https://developer.android.com/guide/app-bundle\n'
' * https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split';
@override
Future<Map<CustomDimensions, String>> get usageValues async {
@ -97,24 +99,7 @@ class BuildApkCommand extends BuildSubCommand {
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
);
validateBuild(androidBuildInfo);
if (buildInfo.isRelease && !androidBuildInfo.splitPerAbi && androidBuildInfo.targetArchs.length > 1) {
final String targetPlatforms = stringsArg('target-platform').join(', ');
globals.printStatus('You are building a fat APK that includes binaries for '
'$targetPlatforms.', emphasis: true, color: TerminalColor.green);
globals.printStatus('If you are deploying the app to the Play Store, '
"it's recommended to use app bundles or split the APK to reduce the APK size.", emphasis: true);
globals.printStatus('To generate an app bundle, run:', emphasis: true, indent: 4);
globals.printStatus('flutter build appbundle '
'--target-platform ${targetPlatforms.replaceAll(' ', '')}',indent: 8);
globals.printStatus('Learn more: https://developer.android.com/guide/app-bundle',indent: 8);
globals.printStatus('To split the APKs per ABI, run:', emphasis: true, indent: 4);
globals.printStatus('flutter build apk '
'--target-platform ${targetPlatforms.replaceAll(' ', '')} '
'--split-per-abi', indent: 8);
globals.printStatus('Learn more: https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split',indent: 8);
}
displayNullSafetyMode(androidBuildInfo.buildInfo);
await androidBuilder.buildApk(
project: FlutterProject.current(),
target: targetFile,

View file

@ -86,6 +86,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
);
validateBuild(androidBuildInfo);
displayNullSafetyMode(androidBuildInfo.buildInfo);
await androidBuilder.buildAab(
project: FlutterProject.current(),
target: targetFile,

View file

@ -97,6 +97,7 @@ class BuildBundleCommand extends BuildSubCommand {
}
final BuildInfo buildInfo = await getBuildInfo();
displayNullSafetyMode(buildInfo);
await bundleBuilder.build(
platform: platform,

View file

@ -72,6 +72,7 @@ class BuildFuchsiaCommand extends BuildSubCommand {
if (!flutterProject.fuchsia.existsSync()) {
throwToolExit('No Fuchsia project is configured.');
}
displayNullSafetyMode(buildInfo);
await buildFuchsia(
fuchsiaProject: flutterProject.fuchsia,
target: targetFile,

View file

@ -110,6 +110,7 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
}
final FlutterCommandResult xcarchiveResult = await super.runCommand();
final BuildInfo buildInfo = await getBuildInfo();
displayNullSafetyMode(buildInfo);
if (exportOptionsPlist == null) {
return xcarchiveResult;

View file

@ -127,7 +127,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
FlutterProject _project;
Future<List<BuildInfo>> get buildInfos async {
Future<List<BuildInfo>> getBuildInfos() async {
final List<BuildInfo> buildInfos = <BuildInfo>[];
if (boolArg('debug')) {
@ -154,7 +154,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
if (boolArg('universal')) {
throwToolExit('--universal has been deprecated, only XCFrameworks are supported.');
}
if ((await buildInfos).isEmpty) {
if ((await getBuildInfos()).isEmpty) {
throwToolExit('At least one of "--debug" or "--profile", or "--release" is required.');
}
}
@ -173,8 +173,9 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
}
final Directory outputDirectory = globals.fs.directory(globals.fs.path.absolute(globals.fs.path.normalize(outputArgument)));
for (final BuildInfo buildInfo in await buildInfos) {
final List<BuildInfo> buildInfos = await getBuildInfos();
displayNullSafetyMode(buildInfos.first);
for (final BuildInfo buildInfo in buildInfos) {
final String productBundleIdentifier = await _project.ios.productBundleIdentifier(buildInfo);
globals.printStatus('Building frameworks for $productBundleIdentifier in ${getNameForBuildMode(buildInfo.mode)} mode...');
final String xcodeBuildConfiguration = toTitleCase(getNameForBuildMode(buildInfo.mode));

View file

@ -43,6 +43,7 @@ class BuildLinuxCommand extends BuildSubCommand {
if (!globals.platform.isLinux) {
throwToolExit('"build linux" only supported on Linux hosts.');
}
displayNullSafetyMode(buildInfo);
await buildLinux(
flutterProject.linux,
buildInfo,

View file

@ -47,6 +47,7 @@ class BuildMacosCommand extends BuildSubCommand {
if (!globals.platform.isMacOS) {
throwToolExit('"build macos" only supported on macOS hosts.');
}
displayNullSafetyMode(buildInfo);
await buildMacOS(
flutterProject: flutterProject,
buildInfo: buildInfo,

View file

@ -84,6 +84,7 @@ class BuildWebCommand extends BuildSubCommand {
if (buildInfo.isDebug) {
throwToolExit('debug builds cannot be built directly for the web. Try using "flutter run"');
}
displayNullSafetyMode(buildInfo);
await buildWeb(
flutterProject,
target,

View file

@ -49,6 +49,7 @@ class BuildWindowsCommand extends BuildSubCommand {
if (!globals.platform.isWindows) {
throwToolExit('"build windows" only supported on Windows hosts.');
}
displayNullSafetyMode(buildInfo);
await buildWindows(
flutterProject.windows,
buildInfo,

View file

@ -661,7 +661,8 @@ abstract class FlutterCommand extends Command<void> {
FlutterOptions.kPerformanceMeasurementFile,
help:
'The name of a file where flutter assemble performance and '
'cached-ness information will be written in a JSON format.'
'cached-ness information will be written in a JSON format.',
hide: hide,
);
}
@ -674,6 +675,7 @@ abstract class FlutterCommand extends Command<void> {
"'--no-daemon' to the gradle wrapper script. This flag will cause the daemon "
'process to terminate after the build is completed',
defaultsTo: true,
hide: hide,
);
}

View file

@ -3,7 +3,9 @@
// found in the LICENSE file.
import 'package:args/args.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/commands/attach.dart';
import 'package:flutter_tools/src/commands/build.dart';
import 'package:flutter_tools/src/commands/build_aar.dart';
import 'package:flutter_tools/src/commands/build_apk.dart';
import 'package:flutter_tools/src/commands/build_appbundle.dart';
@ -47,4 +49,45 @@ void main() {
expect(results.wasParsed('enable-experiment'), true);
}
});
testUsingContext('BuildSubCommand displays current null safety mode', () async {
const BuildInfo unsound = BuildInfo(
BuildMode.debug,
'',
trackWidgetCreation: false,
nullSafetyMode: NullSafetyMode.unsound,
treeShakeIcons: false,
);
const BuildInfo sound = BuildInfo(
BuildMode.debug,
'',
trackWidgetCreation: false,
nullSafetyMode: NullSafetyMode.sound,
treeShakeIcons: false,
);
FakeBuildSubCommand().test(unsound);
expect(testLogger.statusText, contains('Building with unsound null safety'));
testLogger.clear();
FakeBuildSubCommand().test(sound);
expect(testLogger.statusText, contains('💪 Building with sound null safety 💪'));
});
}
class FakeBuildSubCommand extends BuildSubCommand {
@override
String get description => throw UnimplementedError();
@override
String get name => throw UnimplementedError();
void test(BuildInfo buildInfo) {
displayNullSafetyMode(buildInfo);
}
@override
Future<FlutterCommandResult> runCommand() {
throw UnimplementedError();
}
}