mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +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
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
import '../build_info.dart';
|
||||||
import '../commands/build_linux.dart';
|
import '../commands/build_linux.dart';
|
||||||
import '../commands/build_macos.dart';
|
import '../commands/build_macos.dart';
|
||||||
import '../commands/build_windows.dart';
|
import '../commands/build_windows.dart';
|
||||||
@ -52,4 +55,25 @@ abstract class BuildSubCommand extends FlutterCommand {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool get reportNullSafety => true;
|
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.');
|
throwToolExit('Please specify a build mode and try again.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
displayNullSafetyMode(androidBuildInfo.first.buildInfo);
|
||||||
await androidBuilder.buildAar(
|
await androidBuilder.buildAar(
|
||||||
project: _getProject(),
|
project: _getProject(),
|
||||||
target: '', // Not needed because this command only builds Android's code.
|
target: '', // Not needed because this command only builds Android's code.
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
import '../android/android_builder.dart';
|
import '../android/android_builder.dart';
|
||||||
import '../android/build_validation.dart';
|
import '../android/build_validation.dart';
|
||||||
import '../android/gradle_utils.dart';
|
import '../android/gradle_utils.dart';
|
||||||
import '../base/terminal.dart';
|
|
||||||
import '../build_info.dart';
|
import '../build_info.dart';
|
||||||
import '../cache.dart';
|
import '../cache.dart';
|
||||||
import '../globals.dart' as globals;
|
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'
|
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 "
|
"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 "
|
"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
|
@override
|
||||||
Future<Map<CustomDimensions, String>> get usageValues async {
|
Future<Map<CustomDimensions, String>> get usageValues async {
|
||||||
@ -97,24 +99,7 @@ class BuildApkCommand extends BuildSubCommand {
|
|||||||
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
|
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
|
||||||
);
|
);
|
||||||
validateBuild(androidBuildInfo);
|
validateBuild(androidBuildInfo);
|
||||||
|
displayNullSafetyMode(androidBuildInfo.buildInfo);
|
||||||
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);
|
|
||||||
}
|
|
||||||
await androidBuilder.buildApk(
|
await androidBuilder.buildApk(
|
||||||
project: FlutterProject.current(),
|
project: FlutterProject.current(),
|
||||||
target: targetFile,
|
target: targetFile,
|
||||||
|
@ -86,6 +86,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
|
|||||||
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
|
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
|
||||||
);
|
);
|
||||||
validateBuild(androidBuildInfo);
|
validateBuild(androidBuildInfo);
|
||||||
|
displayNullSafetyMode(androidBuildInfo.buildInfo);
|
||||||
await androidBuilder.buildAab(
|
await androidBuilder.buildAab(
|
||||||
project: FlutterProject.current(),
|
project: FlutterProject.current(),
|
||||||
target: targetFile,
|
target: targetFile,
|
||||||
|
@ -97,6 +97,7 @@ class BuildBundleCommand extends BuildSubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final BuildInfo buildInfo = await getBuildInfo();
|
final BuildInfo buildInfo = await getBuildInfo();
|
||||||
|
displayNullSafetyMode(buildInfo);
|
||||||
|
|
||||||
await bundleBuilder.build(
|
await bundleBuilder.build(
|
||||||
platform: platform,
|
platform: platform,
|
||||||
|
@ -72,6 +72,7 @@ class BuildFuchsiaCommand extends BuildSubCommand {
|
|||||||
if (!flutterProject.fuchsia.existsSync()) {
|
if (!flutterProject.fuchsia.existsSync()) {
|
||||||
throwToolExit('No Fuchsia project is configured.');
|
throwToolExit('No Fuchsia project is configured.');
|
||||||
}
|
}
|
||||||
|
displayNullSafetyMode(buildInfo);
|
||||||
await buildFuchsia(
|
await buildFuchsia(
|
||||||
fuchsiaProject: flutterProject.fuchsia,
|
fuchsiaProject: flutterProject.fuchsia,
|
||||||
target: targetFile,
|
target: targetFile,
|
||||||
|
@ -110,6 +110,7 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
|
|||||||
}
|
}
|
||||||
final FlutterCommandResult xcarchiveResult = await super.runCommand();
|
final FlutterCommandResult xcarchiveResult = await super.runCommand();
|
||||||
final BuildInfo buildInfo = await getBuildInfo();
|
final BuildInfo buildInfo = await getBuildInfo();
|
||||||
|
displayNullSafetyMode(buildInfo);
|
||||||
|
|
||||||
if (exportOptionsPlist == null) {
|
if (exportOptionsPlist == null) {
|
||||||
return xcarchiveResult;
|
return xcarchiveResult;
|
||||||
|
@ -127,7 +127,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
|
|
||||||
FlutterProject _project;
|
FlutterProject _project;
|
||||||
|
|
||||||
Future<List<BuildInfo>> get buildInfos async {
|
Future<List<BuildInfo>> getBuildInfos() async {
|
||||||
final List<BuildInfo> buildInfos = <BuildInfo>[];
|
final List<BuildInfo> buildInfos = <BuildInfo>[];
|
||||||
|
|
||||||
if (boolArg('debug')) {
|
if (boolArg('debug')) {
|
||||||
@ -154,7 +154,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
if (boolArg('universal')) {
|
if (boolArg('universal')) {
|
||||||
throwToolExit('--universal has been deprecated, only XCFrameworks are supported.');
|
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.');
|
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)));
|
final Directory outputDirectory = globals.fs.directory(globals.fs.path.absolute(globals.fs.path.normalize(outputArgument)));
|
||||||
|
final List<BuildInfo> buildInfos = await getBuildInfos();
|
||||||
for (final BuildInfo buildInfo in await buildInfos) {
|
displayNullSafetyMode(buildInfos.first);
|
||||||
|
for (final BuildInfo buildInfo in buildInfos) {
|
||||||
final String productBundleIdentifier = await _project.ios.productBundleIdentifier(buildInfo);
|
final String productBundleIdentifier = await _project.ios.productBundleIdentifier(buildInfo);
|
||||||
globals.printStatus('Building frameworks for $productBundleIdentifier in ${getNameForBuildMode(buildInfo.mode)} mode...');
|
globals.printStatus('Building frameworks for $productBundleIdentifier in ${getNameForBuildMode(buildInfo.mode)} mode...');
|
||||||
final String xcodeBuildConfiguration = toTitleCase(getNameForBuildMode(buildInfo.mode));
|
final String xcodeBuildConfiguration = toTitleCase(getNameForBuildMode(buildInfo.mode));
|
||||||
|
@ -43,6 +43,7 @@ class BuildLinuxCommand extends BuildSubCommand {
|
|||||||
if (!globals.platform.isLinux) {
|
if (!globals.platform.isLinux) {
|
||||||
throwToolExit('"build linux" only supported on Linux hosts.');
|
throwToolExit('"build linux" only supported on Linux hosts.');
|
||||||
}
|
}
|
||||||
|
displayNullSafetyMode(buildInfo);
|
||||||
await buildLinux(
|
await buildLinux(
|
||||||
flutterProject.linux,
|
flutterProject.linux,
|
||||||
buildInfo,
|
buildInfo,
|
||||||
|
@ -47,6 +47,7 @@ class BuildMacosCommand extends BuildSubCommand {
|
|||||||
if (!globals.platform.isMacOS) {
|
if (!globals.platform.isMacOS) {
|
||||||
throwToolExit('"build macos" only supported on macOS hosts.');
|
throwToolExit('"build macos" only supported on macOS hosts.');
|
||||||
}
|
}
|
||||||
|
displayNullSafetyMode(buildInfo);
|
||||||
await buildMacOS(
|
await buildMacOS(
|
||||||
flutterProject: flutterProject,
|
flutterProject: flutterProject,
|
||||||
buildInfo: buildInfo,
|
buildInfo: buildInfo,
|
||||||
|
@ -84,6 +84,7 @@ class BuildWebCommand extends BuildSubCommand {
|
|||||||
if (buildInfo.isDebug) {
|
if (buildInfo.isDebug) {
|
||||||
throwToolExit('debug builds cannot be built directly for the web. Try using "flutter run"');
|
throwToolExit('debug builds cannot be built directly for the web. Try using "flutter run"');
|
||||||
}
|
}
|
||||||
|
displayNullSafetyMode(buildInfo);
|
||||||
await buildWeb(
|
await buildWeb(
|
||||||
flutterProject,
|
flutterProject,
|
||||||
target,
|
target,
|
||||||
|
@ -49,6 +49,7 @@ class BuildWindowsCommand extends BuildSubCommand {
|
|||||||
if (!globals.platform.isWindows) {
|
if (!globals.platform.isWindows) {
|
||||||
throwToolExit('"build windows" only supported on Windows hosts.');
|
throwToolExit('"build windows" only supported on Windows hosts.');
|
||||||
}
|
}
|
||||||
|
displayNullSafetyMode(buildInfo);
|
||||||
await buildWindows(
|
await buildWindows(
|
||||||
flutterProject.windows,
|
flutterProject.windows,
|
||||||
buildInfo,
|
buildInfo,
|
||||||
|
@ -661,7 +661,8 @@ abstract class FlutterCommand extends Command<void> {
|
|||||||
FlutterOptions.kPerformanceMeasurementFile,
|
FlutterOptions.kPerformanceMeasurementFile,
|
||||||
help:
|
help:
|
||||||
'The name of a file where flutter assemble performance and '
|
'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 "
|
"'--no-daemon' to the gradle wrapper script. This flag will cause the daemon "
|
||||||
'process to terminate after the build is completed',
|
'process to terminate after the build is completed',
|
||||||
defaultsTo: true,
|
defaultsTo: true,
|
||||||
|
hide: hide,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:args/args.dart';
|
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/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_aar.dart';
|
||||||
import 'package:flutter_tools/src/commands/build_apk.dart';
|
import 'package:flutter_tools/src/commands/build_apk.dart';
|
||||||
import 'package:flutter_tools/src/commands/build_appbundle.dart';
|
import 'package:flutter_tools/src/commands/build_appbundle.dart';
|
||||||
@ -47,4 +49,45 @@ void main() {
|
|||||||
expect(results.wasParsed('enable-experiment'), true);
|
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 New Issue
Block a user