mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
[flutter_tools] describe current null safety build mode (#73426)
This commit is contained in:
parent
5a4df0ad2c
commit
ed66037f51
|
@ -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('');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -97,6 +97,7 @@ class BuildBundleCommand extends BuildSubCommand {
|
|||
}
|
||||
|
||||
final BuildInfo buildInfo = await getBuildInfo();
|
||||
displayNullSafetyMode(buildInfo);
|
||||
|
||||
await bundleBuilder.build(
|
||||
platform: platform,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue