Allow multi-abi shared libraries in APKs and App bundles (#34123)
* Gradle generates ELF shared libraries instead of AOT snapshots.
* `flutter build apk/appbundle` supports multiple `--target-platform` and defaults to `android-arm` and `android-arm64`.
* `flutter build apk` now has a flag called `--split-per-abi`.
diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index e062da5..c9c5c71 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -397,9 +397,24 @@
return LaunchResult.failed();
}
- BuildInfo buildInfo = debuggingOptions.buildInfo;
- if (buildInfo.targetPlatform == null && devicePlatform == TargetPlatform.android_arm64)
- buildInfo = buildInfo.withTargetPlatform(TargetPlatform.android_arm64);
+ AndroidArch androidArch;
+ switch (devicePlatform) {
+ case TargetPlatform.android_arm:
+ androidArch = AndroidArch.armeabi_v7a;
+ break;
+ case TargetPlatform.android_arm64:
+ androidArch = AndroidArch.arm64_v8a;
+ break;
+ case TargetPlatform.android_x64:
+ androidArch = AndroidArch.x86_64;
+ break;
+ case TargetPlatform.android_x86:
+ androidArch = AndroidArch.x86;
+ break;
+ default:
+ printError('Android platforms are only supported.');
+ return LaunchResult.failed();
+ }
if (!prebuiltApplication || androidSdk.licensesAvailable && androidSdk.latestVersion == null) {
printTrace('Building APK');
@@ -407,7 +422,9 @@
await buildApk(
project: project,
target: mainPath,
- buildInfo: buildInfo,
+ androidBuildInfo: AndroidBuildInfo(debuggingOptions.buildInfo,
+ targetArchs: <AndroidArch>[androidArch]
+ ),
);
// Package has been built, so we can get the updated application ID and
// activity name from the .apk.
diff --git a/packages/flutter_tools/lib/src/android/apk.dart b/packages/flutter_tools/lib/src/android/apk.dart
index 8b5b8d9..908c535 100644
--- a/packages/flutter_tools/lib/src/android/apk.dart
+++ b/packages/flutter_tools/lib/src/android/apk.dart
@@ -16,7 +16,7 @@
Future<void> buildApk({
@required FlutterProject project,
@required String target,
- BuildInfo buildInfo = BuildInfo.debug,
+ @required AndroidBuildInfo androidBuildInfo,
}) async {
if (!project.android.isUsingGradle) {
throwToolExit(
@@ -33,7 +33,7 @@
await buildGradleProject(
project: project,
- buildInfo: buildInfo,
+ androidBuildInfo: androidBuildInfo,
target: target,
isBuildingBundle: false,
);
diff --git a/packages/flutter_tools/lib/src/android/app_bundle.dart b/packages/flutter_tools/lib/src/android/app_bundle.dart
index c1e94ab..4f304c1 100644
--- a/packages/flutter_tools/lib/src/android/app_bundle.dart
+++ b/packages/flutter_tools/lib/src/android/app_bundle.dart
@@ -17,7 +17,7 @@
Future<void> buildAppBundle({
@required FlutterProject project,
@required String target,
- BuildInfo buildInfo = BuildInfo.debug,
+ @required AndroidBuildInfo androidBuildInfo,
}) async {
if (!project.android.isUsingGradle) {
throwToolExit(
@@ -42,7 +42,7 @@
return buildGradleProject(
project: project,
- buildInfo: buildInfo,
+ androidBuildInfo: androidBuildInfo,
target: target,
isBuildingBundle: true,
);
diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart
index 62f4475..bf53166 100644
--- a/packages/flutter_tools/lib/src/android/gradle.dart
+++ b/packages/flutter_tools/lib/src/android/gradle.dart
@@ -15,6 +15,7 @@
import '../base/os.dart';
import '../base/platform.dart';
import '../base/process.dart';
+import '../base/terminal.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../cache.dart';
@@ -318,7 +319,7 @@
Future<void> buildGradleProject({
@required FlutterProject project,
- @required BuildInfo buildInfo,
+ @required AndroidBuildInfo androidBuildInfo,
@required String target,
@required bool isBuildingBundle,
}) async {
@@ -330,7 +331,7 @@
// and can be overwritten with flutter build command.
// The default Gradle script reads the version name and number
// from the local.properties file.
- updateLocalProperties(project: project, buildInfo: buildInfo);
+ updateLocalProperties(project: project, buildInfo: androidBuildInfo.buildInfo);
final String gradle = await _ensureGradle(project);
@@ -342,7 +343,7 @@
case FlutterPluginVersion.managed:
// Fall through. Managed plugin builds the same way as plugin v2.
case FlutterPluginVersion.v2:
- return _buildGradleProjectV2(project, gradle, buildInfo, target, isBuildingBundle);
+ return _buildGradleProjectV2(project, gradle, androidBuildInfo, target, isBuildingBundle);
}
}
@@ -391,11 +392,12 @@
Future<void> _buildGradleProjectV2(
FlutterProject flutterProject,
String gradle,
- BuildInfo buildInfo,
+ AndroidBuildInfo androidBuildInfo,
String target,
bool isBuildingBundle,
) async {
final GradleProject project = await _gradleProject();
+ final BuildInfo buildInfo = androidBuildInfo.buildInfo;
String assembleTask;
@@ -453,12 +455,13 @@
command.add('-Pfilesystem-roots=${buildInfo.fileSystemRoots.join('|')}');
if (buildInfo.fileSystemScheme != null)
command.add('-Pfilesystem-scheme=${buildInfo.fileSystemScheme}');
- if (buildInfo.buildSharedLibrary) {
- command.add('-Pbuild-shared-library=true');
+ if (androidBuildInfo.splitPerAbi)
+ command.add('-Psplit-per-abi=true');
+ if (androidBuildInfo.targetArchs.isNotEmpty) {
+ final String targetPlatforms = androidBuildInfo.targetArchs
+ .map(getPlatformNameForAndroidArch).join(',');
+ command.add('-Ptarget-platform=$targetPlatforms');
}
- if (buildInfo.targetPlatform != null)
- command.add('-Ptarget-platform=${getNameForTargetPlatform(buildInfo.targetPlatform)}');
-
command.add(assembleTask);
bool potentialAndroidXFailure = false;
final Stopwatch sw = Stopwatch()..start();
@@ -508,24 +511,27 @@
flutterUsage.sendTiming('build', 'gradle-v2', Duration(milliseconds: sw.elapsedMilliseconds));
if (!isBuildingBundle) {
- final File apkFile = _findApkFile(project, buildInfo);
- if (apkFile == null)
+ final Iterable<File> apkFiles = _findApkFiles(project, androidBuildInfo);
+ if (apkFiles.isEmpty)
throwToolExit('Gradle build failed to produce an Android package.');
- // Copy the APK to app.apk, so `flutter run`, `flutter install`, etc. can find it.
- apkFile.copySync(project.apkDirectory.childFile('app.apk').path);
+ // Copy the first APK to app.apk, so `flutter run`, `flutter install`, etc. can find it.
+ // TODO(blasten): Handle multiple APKs.
+ apkFiles.first.copySync(project.apkDirectory.childFile('app.apk').path);
printTrace('calculateSha: ${project.apkDirectory}/app.apk');
final File apkShaFile = project.apkDirectory.childFile('app.apk.sha1');
- apkShaFile.writeAsStringSync(_calculateSha(apkFile));
+ apkShaFile.writeAsStringSync(_calculateSha(apkFiles.first));
- String appSize;
- if (buildInfo.mode == BuildMode.debug) {
- appSize = '';
- } else {
- appSize = ' (${getSizeAsMB(apkFile.lengthSync())})';
+ for (File apkFile in apkFiles) {
+ String appSize;
+ if (buildInfo.mode == BuildMode.debug) {
+ appSize = '';
+ } else {
+ appSize = ' (${getSizeAsMB(apkFile.lengthSync())})';
+ }
+ printStatus('Built ${fs.path.relative(apkFile.path)}$appSize.',
+ color: TerminalColor.green);
}
- printStatus('Built ${fs.path.relative(apkFile.path)}$appSize.');
-
} else {
final File bundleFile = _findBundleFile(project, buildInfo);
if (bundleFile == null)
@@ -537,28 +543,38 @@
} else {
appSize = ' (${getSizeAsMB(bundleFile.lengthSync())})';
}
- printStatus('Built ${fs.path.relative(bundleFile.path)}$appSize.');
+ printStatus('Built ${fs.path.relative(bundleFile.path)}$appSize.',
+ color: TerminalColor.green);
}
}
-File _findApkFile(GradleProject project, BuildInfo buildInfo) {
- final String apkFileName = project.apkFileFor(buildInfo);
- if (apkFileName == null)
- return null;
- File apkFile = fs.file(fs.path.join(project.apkDirectory.path, apkFileName));
- if (apkFile.existsSync())
- return apkFile;
- final String modeName = camelCase(buildInfo.modeName);
- apkFile = fs.file(fs.path.join(project.apkDirectory.path, modeName, apkFileName));
- if (apkFile.existsSync())
- return apkFile;
- if (buildInfo.flavor != null) {
- // Android Studio Gradle plugin v3 adds flavor to path.
- apkFile = fs.file(fs.path.join(project.apkDirectory.path, buildInfo.flavor, modeName, apkFileName));
+Iterable<File> _findApkFiles(GradleProject project, AndroidBuildInfo androidBuildInfo) {
+ final Iterable<String> apkFileNames = project.apkFilesFor(androidBuildInfo);
+ if (apkFileNames.isEmpty)
+ return const <File>[];
+
+ return apkFileNames.map<File>((String apkFileName) {
+ File apkFile = project.apkDirectory.childFile(apkFileName);
if (apkFile.existsSync())
return apkFile;
- }
- return null;
+ final BuildInfo buildInfo = androidBuildInfo.buildInfo;
+ final String modeName = camelCase(buildInfo.modeName);
+ apkFile = project.apkDirectory
+ .childDirectory(modeName)
+ .childFile(apkFileName);
+ if (apkFile.existsSync())
+ return apkFile;
+ if (buildInfo.flavor != null) {
+ // Android Studio Gradle plugin v3 adds flavor to path.
+ apkFile = project.apkDirectory
+ .childDirectory(buildInfo.flavor)
+ .childDirectory(modeName)
+ .childFile(apkFileName);
+ if (apkFile.existsSync())
+ return apkFile;
+ }
+ return null;
+ });
}
File _findBundleFile(GradleProject project, BuildInfo buildInfo) {
@@ -567,12 +583,12 @@
if (bundleFileName == null)
return null;
final String modeName = camelCase(buildInfo.modeName);
- File bundleFile = fs.file(fs.path.join(project.bundleDirectory.path, modeName, bundleFileName));
+ File bundleFile = project.bundleDirectory.childDirectory(modeName).childFile(bundleFileName);
if (bundleFile.existsSync())
return bundleFile;
if (buildInfo.flavor != null) {
// Android Studio Gradle plugin v3 adds the flavor to the path. For the bundle the folder name is the flavor plus the mode name.
- bundleFile = fs.file(fs.path.join(project.bundleDirectory.path, buildInfo.flavor + modeName, bundleFileName));
+ bundleFile = project.bundleDirectory.childDirectory(buildInfo.flavor + modeName).childFile(bundleFileName);
if (bundleFile.existsSync())
return bundleFile;
}
@@ -661,13 +677,20 @@
return 'assemble${toTitleCase(productFlavor)}${toTitleCase(buildType)}';
}
- String apkFileFor(BuildInfo buildInfo) {
- final String buildType = _buildTypeFor(buildInfo);
- final String productFlavor = _productFlavorFor(buildInfo);
+ Iterable<String> apkFilesFor(AndroidBuildInfo androidBuildInfo) {
+ final String buildType = _buildTypeFor(androidBuildInfo.buildInfo);
+ final String productFlavor = _productFlavorFor(androidBuildInfo.buildInfo);
if (buildType == null || productFlavor == null)
- return null;
+ return const <String>[];
+
final String flavorString = productFlavor.isEmpty ? '' : '-' + productFlavor;
- return 'app$flavorString-$buildType.apk';
+ if (androidBuildInfo.splitPerAbi) {
+ return androidBuildInfo.targetArchs.map<String>((AndroidArch arch) {
+ final String abi = getNameForAndroidArch(arch);
+ return 'app$flavorString-$abi-$buildType.apk';
+ });
+ }
+ return <String>['app$flavorString-$buildType.apk'];
}
String bundleTaskFor(BuildInfo buildInfo) {
diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart
index 4b46edb..1908cb3 100644
--- a/packages/flutter_tools/lib/src/base/build.dart
+++ b/packages/flutter_tools/lib/src/base/build.dart
@@ -137,7 +137,7 @@
final String aotSharedLibrary = fs.path.join(outputDir.path, 'app.so');
outputPaths.add(aotSharedLibrary);
genSnapshotArgs.add('--snapshot_kind=app-aot-elf');
- genSnapshotArgs.add('--assembly=$aotSharedLibrary');
+ genSnapshotArgs.add('--elf=$aotSharedLibrary');
} else {
// Blob AOT snapshot.
final String vmSnapshotData = fs.path.join(outputDir.path, 'vm_snapshot_data');
diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart
index 8379e81..e346019 100644
--- a/packages/flutter_tools/lib/src/build_info.dart
+++ b/packages/flutter_tools/lib/src/build_info.dart
@@ -17,8 +17,6 @@
this.compilationTraceFilePath,
this.extraFrontEndOptions,
this.extraGenSnapshotOptions,
- this.buildSharedLibrary,
- this.targetPlatform,
this.fileSystemRoots,
this.fileSystemScheme,
this.buildNumber,
@@ -50,12 +48,6 @@
/// Extra command-line options for gen_snapshot.
final String extraGenSnapshotOptions;
- /// Whether to prefer AOT compiling to a *so file.
- final bool buildSharedLibrary;
-
- /// Target platform for the build (e.g. android_arm versus android_arm64).
- final TargetPlatform targetPlatform;
-
/// Internal version number (not displayed to users).
/// Each build must have a unique number to differentiate it from previous builds.
/// It is used to determine whether one build is more recent than another, with higher numbers indicating more recent build.
@@ -98,15 +90,31 @@
bool get supportsSimulator => isEmulatorBuildMode(mode);
String get modeName => getModeName(mode);
String get friendlyModeName => getFriendlyModeName(mode);
+}
- BuildInfo withTargetPlatform(TargetPlatform targetPlatform) =>
- BuildInfo(mode, flavor,
- trackWidgetCreation: trackWidgetCreation,
- compilationTraceFilePath: compilationTraceFilePath,
- extraFrontEndOptions: extraFrontEndOptions,
- extraGenSnapshotOptions: extraGenSnapshotOptions,
- buildSharedLibrary: buildSharedLibrary,
- targetPlatform: targetPlatform);
+/// Information about an Android build to be performed or used.
+class AndroidBuildInfo {
+ const AndroidBuildInfo(
+ this.buildInfo, {
+ this.targetArchs = const <AndroidArch>[
+ AndroidArch.armeabi_v7a,
+ AndroidArch.arm64_v8a,
+ ],
+ this.splitPerAbi = false,
+ });
+
+ // The build info containing the mode and flavor.
+ final BuildInfo buildInfo;
+
+ /// Whether to split the shared library per ABI.
+ ///
+ /// When this is false, multiple ABIs will be contained within one primary
+ /// build artifact. When this is true, multiple build artifacts (one per ABI)
+ /// will be produced.
+ final bool splitPerAbi;
+
+ /// The target platforms for the build.
+ final Iterable<AndroidArch> targetArchs;
}
/// The type of build.
@@ -254,6 +262,13 @@
arm64,
}
+enum AndroidArch {
+ armeabi_v7a,
+ arm64_v8a,
+ x86,
+ x86_64,
+}
+
/// The default set of iOS device architectures to build for.
const List<IOSArch> defaultIOSArchs = <IOSArch>[
IOSArch.arm64,
@@ -335,6 +350,51 @@
return null;
}
+AndroidArch getAndroidArchForName(String platform) {
+ switch (platform) {
+ case 'android-arm':
+ return AndroidArch.armeabi_v7a;
+ case 'android-arm64':
+ return AndroidArch.arm64_v8a;
+ case 'android-x64':
+ return AndroidArch.x86_64;
+ case 'android-x86':
+ return AndroidArch.x86;
+ }
+ assert(false);
+ return null;
+}
+
+String getNameForAndroidArch(AndroidArch arch) {
+ switch (arch) {
+ case AndroidArch.armeabi_v7a:
+ return 'armeabi-v7a';
+ case AndroidArch.arm64_v8a:
+ return 'arm64-v8a';
+ case AndroidArch.x86_64:
+ return 'x86_64';
+ case AndroidArch.x86:
+ return 'x86';
+ }
+ assert(false);
+ return null;
+}
+
+String getPlatformNameForAndroidArch(AndroidArch arch) {
+ switch (arch) {
+ case AndroidArch.armeabi_v7a:
+ return 'android-arm';
+ case AndroidArch.arm64_v8a:
+ return 'android-arm64';
+ case AndroidArch.x86_64:
+ return 'android-x64';
+ case AndroidArch.x86:
+ return 'android-x86';
+ }
+ assert(false);
+ return null;
+}
+
HostPlatform getCurrentHostPlatform() {
if (platform.isMacOS)
return HostPlatform.darwin_x64;
diff --git a/packages/flutter_tools/lib/src/commands/build_apk.dart b/packages/flutter_tools/lib/src/commands/build_apk.dart
index 1d7fbff..5d9cbe8 100644
--- a/packages/flutter_tools/lib/src/commands/build_apk.dart
+++ b/packages/flutter_tools/lib/src/commands/build_apk.dart
@@ -5,6 +5,9 @@
import 'dart:async';
import '../android/apk.dart';
+import '../base/terminal.dart';
+import '../build_info.dart';
+import '../globals.dart';
import '../project.dart';
import '../runner/flutter_command.dart' show DevelopmentArtifact, FlutterCommandResult;
import 'build.dart';
@@ -21,12 +24,14 @@
argParser
..addFlag('track-widget-creation', negatable: false, hide: !verboseHelp)
- ..addFlag('build-shared-library',
+ ..addFlag('split-per-abi',
negatable: false,
- help: 'Whether to prefer compiling to a *.so file (android only).',
+ help: 'Whether to split the APKs per ABIs.'
+ 'To learn more, see: https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split',
)
- ..addOption('target-platform',
- defaultsTo: 'android-arm',
+ ..addMultiOption('target-platform',
+ splitCommas: true,
+ defaultsTo: <String>['android-arm', 'android-arm64'],
allowed: <String>['android-arm', 'android-arm64', 'android-x86', 'android-x64'],
help: 'The target platform for which the app is compiled.',
);
@@ -49,10 +54,33 @@
@override
Future<FlutterCommandResult> runCommand() async {
+ final BuildInfo buildInfo = getBuildInfo();
+ final AndroidBuildInfo androidBuildInfo = AndroidBuildInfo(buildInfo,
+ splitPerAbi: argResults['split-per-abi'],
+ targetArchs: argResults['target-platform'].map<AndroidArch>(getAndroidArchForName)
+ );
+
+ if (buildInfo.isRelease && !androidBuildInfo.splitPerAbi && androidBuildInfo.targetArchs.length > 1) {
+ final String targetPlatforms = argResults['target-platform'].join(', ');
+
+ printStatus('You are building a fat APK that includes binaries for '
+ '$targetPlatforms.', emphasis: true, color: TerminalColor.green);
+ 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);
+ printStatus('To generate an app bundle, run:', emphasis: true, indent: 4);
+ printStatus('flutter build appbundle '
+ '--target-platform ${targetPlatforms.replaceAll(' ', '')}',indent: 8);
+ printStatus('Learn more on: https://developer.android.com/guide/app-bundle',indent: 8);
+ printStatus('To split the APKs per ABI, run:', emphasis: true, indent: 4);
+ printStatus('flutter build apk '
+ '--target-platform ${targetPlatforms.replaceAll(' ', '')} '
+ '--split-per-abi', indent: 8);
+ printStatus('Learn more on: https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split',indent: 8);
+ }
await buildApk(
project: FlutterProject.current(),
target: targetFile,
- buildInfo: getBuildInfo(),
+ androidBuildInfo: androidBuildInfo,
);
return null;
}
diff --git a/packages/flutter_tools/lib/src/commands/build_appbundle.dart b/packages/flutter_tools/lib/src/commands/build_appbundle.dart
index dcc9d4a..76c5ad1 100644
--- a/packages/flutter_tools/lib/src/commands/build_appbundle.dart
+++ b/packages/flutter_tools/lib/src/commands/build_appbundle.dart
@@ -5,6 +5,7 @@
import 'dart:async';
import '../android/app_bundle.dart';
+import '../build_info.dart';
import '../project.dart';
import '../runner/flutter_command.dart' show FlutterCommandResult;
import 'build.dart';
@@ -20,18 +21,11 @@
argParser
..addFlag('track-widget-creation', negatable: false, hide: !verboseHelp)
- ..addFlag(
- 'build-shared-library',
- negatable: false,
- help: 'Whether to prefer compiling to a *.so file (android only).',
- )
- ..addOption(
- 'target-platform',
+ ..addMultiOption('target-platform',
+ splitCommas: true,
+ defaultsTo: <String>['android-arm', 'android-arm64'],
allowed: <String>['android-arm', 'android-arm64'],
- help: 'The target platform for which the app is compiled.\n'
- 'By default, the bundle will include \'arm\' and \'arm64\', '
- 'which is the recommended configuration for app bundles.\n'
- 'For more, see https://developer.android.com/distribute/best-practices/develop/64-bit',
+ help: 'The target platform for which the app is compiled.',
);
}
@@ -47,10 +41,13 @@
@override
Future<FlutterCommandResult> runCommand() async {
+ final AndroidBuildInfo androidBuildInfo = AndroidBuildInfo(getBuildInfo(),
+ targetArchs: argResults['target-platform'].map<AndroidArch>(getAndroidArchForName)
+ );
await buildAppBundle(
project: FlutterProject.current(),
target: targetFile,
- buildInfo: getBuildInfo(),
+ androidBuildInfo: androidBuildInfo,
);
return null;
}
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index 9f36386..62535d0 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -387,8 +387,7 @@
final BuildInfo debugBuildInfo = BuildInfo(BuildMode.debug, buildInfo.flavor,
trackWidgetCreation: buildInfo.trackWidgetCreation,
extraFrontEndOptions: buildInfo.extraFrontEndOptions,
- extraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions,
- buildSharedLibrary: buildInfo.buildSharedLibrary);
+ extraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions);
final XcodeBuildResult buildResult = await buildXcodeProject(
app: app,
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index b39e674..634d4a8 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -320,12 +320,6 @@
}
BuildInfo getBuildInfo() {
- TargetPlatform targetPlatform;
- if (argParser.options.containsKey('target-platform') &&
- argResults['target-platform'] != 'default') {
- targetPlatform = getTargetPlatformForName(argResults['target-platform']);
- }
-
final bool trackWidgetCreation = argParser.options.containsKey('track-widget-creation')
? argResults['track-widget-creation']
: false;
@@ -362,10 +356,6 @@
extraGenSnapshotOptions: argParser.options.containsKey(FlutterOptions.kExtraGenSnapshotOptions)
? argResults[FlutterOptions.kExtraGenSnapshotOptions]
: null,
- buildSharedLibrary: argParser.options.containsKey('build-shared-library')
- ? argResults['build-shared-library']
- : false,
- targetPlatform: targetPlatform,
fileSystemRoots: argParser.options.containsKey(FlutterOptions.kFileSystemRoot)
? argResults[FlutterOptions.kFileSystemRoot] : null,
fileSystemScheme: argParser.options.containsKey(FlutterOptions.kFileSystemScheme)