Revert "Generate ELF shared libraries and allow multi-abi libs in APKs and App bundles (#33696)" (#34121)
diff --git a/dev/devicelab/bin/tasks/gradle_plugin_test.dart b/dev/devicelab/bin/tasks/gradle_plugin_test.dart
index c71a01d..15939ab 100644
--- a/dev/devicelab/bin/tasks/gradle_plugin_test.dart
+++ b/dev/devicelab/bin/tasks/gradle_plugin_test.dart
@@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'dart:async';
-import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
@@ -47,263 +46,6 @@
print('\nUsing JAVA_HOME=$javaHome');
try {
- await runPluginProjectTest((FlutterPluginProject pluginProject) async {
- section('APK content for task assembleDebug without explicit target platform');
- await pluginProject.runGradleTask('assembleDebug');
-
- if (!pluginProject.hasDebugApk)
- throw TaskResult.failure(
- 'Gradle did not produce a debug apk file at: ${pluginProject.debugApkPath}');
-
- final Iterable<String> apkFiles = await pluginProject.getFilesInApk(pluginProject.debugApkPath);
-
- _checkItContains<String>(<String>[
- 'AndroidManifest.xml',
- 'classes.dex',
- 'assets/flutter_assets/isolate_snapshot_data',
- 'assets/flutter_assets/kernel_blob.bin',
- 'assets/flutter_assets/vm_snapshot_data',
- 'lib/arm64-v8a/libflutter.so',
- 'lib/armeabi-v7a/libflutter.so',
- // Debug mode intentionally includes `x86` and `x86_64`.
- 'lib/x86/libflutter.so',
- 'lib/x86_64/libflutter.so',
- ], apkFiles);
-
- _checkItDoesNotContain<String>(<String>[
- 'lib/arm64-v8a/libapp.so',
- 'lib/armeabi-v7a/libapp.so',
- 'lib/x86/libapp.so',
- 'lib/x86_64/libapp.so',
- ], apkFiles);
- });
-
- await runPluginProjectTest((FlutterPluginProject pluginProject) async {
- section('APK content for task assembleDebug with target platform = android-arm');
- await pluginProject.runGradleTask('assembleDebug',
- options: <String>['-Ptarget-platform=android-arm']);
-
- if (!pluginProject.hasDebugApk)
- throw TaskResult.failure(
- 'Gradle did not produce a debug apk file at: ${pluginProject.debugApkPath}');
-
- final Iterable<String> apkFiles = await pluginProject.getFilesInApk(pluginProject.debugApkPath);
-
- _checkItContains<String>(<String>[
- 'AndroidManifest.xml',
- 'classes.dex',
- 'assets/flutter_assets/isolate_snapshot_data',
- 'assets/flutter_assets/kernel_blob.bin',
- 'assets/flutter_assets/vm_snapshot_data',
- 'lib/armeabi-v7a/libflutter.so',
- // Debug mode intentionally includes `x86` and `x86_64`.
- 'lib/x86/libflutter.so',
- 'lib/x86_64/libflutter.so',
- ], apkFiles);
-
- _checkItDoesNotContain<String>(<String>[
- 'lib/armeabi-v7a/libapp.so',
- 'lib/x86/libapp.so',
- 'lib/x86_64/libapp.so',
- ], apkFiles);
- });
-
- await runPluginProjectTest((FlutterPluginProject pluginProject) async {
- section('APK content for task assembleRelease without explicit target platform');
- await pluginProject.runGradleTask('assembleRelease');
-
- if (!pluginProject.hasReleaseApk)
- throw TaskResult.failure(
- 'Gradle did not produce a release apk file at: ${pluginProject.releaseApkPath}');
-
- final Iterable<String> apkFiles = await pluginProject.getFilesInApk(pluginProject.releaseApkPath);
-
- _checkItContains<String>(<String>[
- 'AndroidManifest.xml',
- 'classes.dex',
- 'lib/arm64-v8a/libflutter.so',
- 'lib/arm64-v8a/libapp.so',
- 'lib/armeabi-v7a/libflutter.so',
- 'lib/armeabi-v7a/libapp.so',
- ], apkFiles);
-
- _checkItDoesNotContain<String>(<String>[
- 'assets/flutter_assets/isolate_snapshot_data',
- 'assets/flutter_assets/kernel_blob.bin',
- 'assets/flutter_assets/vm_snapshot_data',
- ], apkFiles);
- });
-
- await runPluginProjectTest((FlutterPluginProject pluginProject) async {
- section('APK content for task assembleRelease with target platform = android-arm');
- await pluginProject.runGradleTask('assembleRelease',
- options: <String>['-Ptarget-platform=android-arm']);
-
- if (!pluginProject.hasReleaseApk)
- throw TaskResult.failure(
- 'Gradle did not produce a release apk file at: ${pluginProject.releaseApkPath}');
-
- final Iterable<String> apkFiles = await pluginProject.getFilesInApk(pluginProject.releaseApkPath);
-
- _checkItContains<String>(<String>[
- 'AndroidManifest.xml',
- 'classes.dex',
- 'lib/armeabi-v7a/libflutter.so',
- 'lib/armeabi-v7a/libapp.so',
- ], apkFiles);
-
- _checkItDoesNotContain<String>(<String>[
- 'lib/arm64-v8a/libflutter.so',
- 'lib/arm64-v8a/libapp.so',
- 'assets/flutter_assets/isolate_snapshot_data',
- 'assets/flutter_assets/kernel_blob.bin',
- 'assets/flutter_assets/vm_snapshot_data',
- ], apkFiles);
- });
-
- await runPluginProjectTest((FlutterPluginProject pluginProject) async {
- section('APK content for task assembleRelease with target platform = android-arm64');
- await pluginProject.runGradleTask('assembleRelease',
- options: <String>['-Ptarget-platform=android-arm64']);
-
- if (!pluginProject.hasReleaseApk)
- throw TaskResult.failure(
- 'Gradle did not produce a release apk file at: ${pluginProject.releaseApkPath}');
-
- final Iterable<String> apkFiles = await pluginProject.getFilesInApk(pluginProject.releaseApkPath);
-
- _checkItContains<String>(<String>[
- 'AndroidManifest.xml',
- 'classes.dex',
- 'lib/arm64-v8a/libflutter.so',
- 'lib/arm64-v8a/libapp.so',
- ], apkFiles);
-
- _checkItDoesNotContain<String>(<String>[
- 'lib/armeabi-v7a/libflutter.so',
- 'lib/armeabi-v7a/libapp.so',
- 'assets/flutter_assets/isolate_snapshot_data',
- 'assets/flutter_assets/kernel_blob.bin',
- 'assets/flutter_assets/vm_snapshot_data',
- ], apkFiles);
- });
-
- await runPluginProjectTest((FlutterPluginProject pluginProject) async {
- section('APK content for task assembleRelease with target platform = android-arm, android-arm64');
- await pluginProject.runGradleTask('assembleRelease',
- options: <String>['-Ptarget-platform=android-arm,android-arm64']);
-
- if (!pluginProject.hasReleaseApk)
- throw TaskResult.failure(
- 'Gradle did not produce a release apk at: ${pluginProject.releaseApkPath}');
-
- final Iterable<String> apkFiles = await pluginProject.getFilesInApk(pluginProject.releaseApkPath);
-
- _checkItContains<String>(<String>[
- 'AndroidManifest.xml',
- 'classes.dex',
- 'lib/armeabi-v7a/libflutter.so',
- 'lib/armeabi-v7a/libapp.so',
- 'lib/arm64-v8a/libflutter.so',
- 'lib/arm64-v8a/libapp.so',
- ], apkFiles);
-
- _checkItDoesNotContain<String>(<String>[
- 'assets/flutter_assets/isolate_snapshot_data',
- 'assets/flutter_assets/kernel_blob.bin',
- 'assets/flutter_assets/vm_snapshot_data',
- ], apkFiles);
- });
-
- await runPluginProjectTest((FlutterPluginProject pluginProject) async {
- section('APK content for task assembleRelease with '
- 'target platform = android-arm, android-arm64 and split per ABI');
- await pluginProject.runGradleTask('assembleRelease',
- options: <String>['-Ptarget-platform=android-arm,android-arm64', '-Psplit-per-abi=true']);
-
- if (!pluginProject.hasReleaseArmApk)
- throw TaskResult.failure(
- 'Gradle did not produce a release apk at: ${pluginProject.releaseArmApkPath}');
-
- final Iterable<String> armApkFiles = await pluginProject.getFilesInApk(pluginProject.releaseArmApkPath);
-
- _checkItContains<String>(<String>[
- 'AndroidManifest.xml',
- 'classes.dex',
- 'lib/armeabi-v7a/libflutter.so',
- 'lib/armeabi-v7a/libapp.so',
- ], armApkFiles);
-
- _checkItDoesNotContain<String>(<String>[
- 'assets/flutter_assets/isolate_snapshot_data',
- 'assets/flutter_assets/kernel_blob.bin',
- 'assets/flutter_assets/vm_snapshot_data',
- ], armApkFiles);
-
- if (!pluginProject.hasReleaseArm64Apk)
- throw TaskResult.failure(
- 'Gradle did not produce a release apk at: ${pluginProject.releaseArm64ApkPath}');
-
- final Iterable<String> arm64ApkFiles = await pluginProject.getFilesInApk(pluginProject.releaseArm64ApkPath);
-
- _checkItContains<String>(<String>[
- 'AndroidManifest.xml',
- 'classes.dex',
- 'lib/arm64-v8a/libflutter.so',
- 'lib/arm64-v8a/libapp.so',
- ], arm64ApkFiles);
-
- _checkItDoesNotContain<String>(<String>[
- 'assets/flutter_assets/isolate_snapshot_data',
- 'assets/flutter_assets/kernel_blob.bin',
- 'assets/flutter_assets/vm_snapshot_data',
- ], arm64ApkFiles);
- });
-
- await runPluginProjectTest((FlutterPluginProject pluginProject) async {
- section('App bundle content for task bundleRelease without explicit target platform');
- await pluginProject.runGradleTask('bundleRelease');
-
- if (!pluginProject.hasReleaseBundle)
- throw TaskResult.failure(
- 'Gradle did not produce a release aab file at: ${pluginProject.releaseBundlePath}');
-
- final Iterable<String> bundleFiles = await pluginProject.getFilesInAppBundle(pluginProject.releaseBundlePath);
-
- _checkItContains<String>(<String>[
- 'base/manifest/AndroidManifest.xml',
- 'base/dex/classes.dex',
- 'base/lib/arm64-v8a/libapp.so',
- 'base/lib/arm64-v8a/libflutter.so',
- 'base/lib/armeabi-v7a/libapp.so',
- 'base/lib/armeabi-v7a/libflutter.so',
- ], bundleFiles);
- });
-
- await runPluginProjectTest((FlutterPluginProject pluginProject) async {
- section('App bundle content for task bundleRelease with target platform = android-arm');
- await pluginProject.runGradleTask('bundleRelease',
- options: <String>['-Ptarget-platform=android-arm']);
-
- if (!pluginProject.hasReleaseBundle)
- throw TaskResult.failure(
- 'Gradle did not produce a release aab file at: ${pluginProject.releaseBundlePath}');
-
- final Iterable<String> bundleFiles = await pluginProject.getFilesInAppBundle(pluginProject.releaseBundlePath);
-
- _checkItContains<String>(<String>[
- 'base/manifest/AndroidManifest.xml',
- 'base/dex/classes.dex',
- 'base/lib/armeabi-v7a/libapp.so',
- 'base/lib/armeabi-v7a/libflutter.so',
- ], bundleFiles);
-
- _checkItDoesNotContain<String>(<String>[
- 'base/lib/arm64-v8a/libapp.so',
- 'base/lib/arm64-v8a/libflutter.so',
- ], bundleFiles);
- });
-
await runProjectTest((FlutterProject project) async {
section('gradlew assembleDebug');
await project.runGradleTask('assembleDebug');
@@ -338,9 +80,32 @@
'release',
targetPlatform);
- final String sharedLibrary = path.join(androidArmSnapshotPath, 'app.so');
- if (!File(sharedLibrary).existsSync()) {
- throw TaskResult.failure('Shared library doesn\'t exist');
+ final String isolateSnapshotData =
+ path.join(androidArmSnapshotPath, 'isolate_snapshot_data');
+ if (!File(isolateSnapshotData).existsSync()) {
+ throw TaskResult.failure(
+ 'Snapshot doesn\'t exist: $isolateSnapshotData');
+ }
+
+ final String isolateSnapshotInstr =
+ path.join(androidArmSnapshotPath, 'isolate_snapshot_instr');
+ if (!File(isolateSnapshotInstr).existsSync()) {
+ throw TaskResult.failure(
+ 'Snapshot doesn\'t exist: $isolateSnapshotInstr');
+ }
+
+ final String vmSnapshotData =
+ path.join(androidArmSnapshotPath, 'vm_snapshot_data');
+ if (!File(isolateSnapshotData).existsSync()) {
+ throw TaskResult.failure(
+ 'Snapshot doesn\'t exist: $vmSnapshotData');
+ }
+
+ final String vmSnapshotInstr =
+ path.join(androidArmSnapshotPath, 'vm_snapshot_instr');
+ if (!File(isolateSnapshotData).existsSync()) {
+ throw TaskResult.failure(
+ 'Snapshot doesn\'t exist: $vmSnapshotInstr');
}
}
});
@@ -418,23 +183,6 @@
});
}
-
-void _checkItContains<T>(Iterable<T> values, Iterable<T> collection) {
- for (T value in values) {
- if (!collection.contains(value)) {
- throw TaskResult.failure('Expected to find `$value` in `$collection`.');
- }
- }
-}
-
-void _checkItDoesNotContain<T>(Iterable<T> values, Iterable<T> collection) {
- for (T value in values) {
- if (collection.contains(value)) {
- throw TaskResult.failure('Did not expect to find `$value` in `$collection`.');
- }
- }
-}
-
TaskResult _failure(String message, ProcessResult result) {
print('Unexpected process result:');
print('Exit code: ${result.exitCode}');
@@ -540,37 +288,12 @@
String get examplePath => path.join(rootPath, 'example');
String get exampleAndroidPath => path.join(examplePath, 'android');
String get debugApkPath => path.join(examplePath, 'build', 'app', 'outputs', 'apk', 'debug', 'app-debug.apk');
- String get releaseApkPath => path.join(examplePath, 'build', 'app', 'outputs', 'apk', 'release', 'app-release.apk');
- String get releaseArmApkPath => path.join(examplePath, 'build', 'app', 'outputs', 'apk', 'release', 'app-armeabi-v7a-release.apk');
- String get releaseArm64ApkPath => path.join(examplePath, 'build', 'app', 'outputs', 'apk', 'release', 'app-arm64-v8a-release.apk');
- String get releaseBundlePath => path.join(examplePath, 'build', 'app', 'outputs', 'bundle', 'release', 'app.aab');
-
- bool get hasDebugApk => File(debugApkPath).existsSync();
- bool get hasReleaseApk => File(releaseApkPath).existsSync();
- bool get hasReleaseArmApk => File(releaseArmApkPath).existsSync();
- bool get hasReleaseArm64Apk => File(releaseArm64ApkPath).existsSync();
- bool get hasReleaseBundle => File(releaseBundlePath).existsSync();
Future<void> runGradleTask(String task, {List<String> options}) async {
return _runGradleTask(workingDirectory: exampleAndroidPath, task: task, options: options);
}
- Future<Iterable<String>> getFilesInApk(String apk) async {
- final Process unzip = await startProcess(
- 'unzip',
- <String>['-v', apk],
- isBot: false, // we just want to test the output, not have any debugging info
- );
- return unzip.stdout
- .transform(utf8.decoder)
- .transform(const LineSplitter())
- .map((String line) => line.split(' ').last)
- .toList();
- }
-
- Future<Iterable<String>> getFilesInAppBundle(String bundle) {
- return getFilesInApk(bundle);
- }
+ bool get hasDebugApk => File(debugApkPath).existsSync();
}
Future<void> _runGradleTask({String workingDirectory, String task, List<String> options}) async {
diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml
index e8f090d..2f56149 100644
--- a/dev/devicelab/pubspec.yaml
+++ b/dev/devicelab/pubspec.yaml
@@ -5,7 +5,7 @@
environment:
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
- sdk: ">=2.3.0 <3.0.0"
+ sdk: ">=2.2.2 <3.0.0"
dependencies:
args: 1.5.2
diff --git a/packages/flutter_tools/gradle/flutter.gradle b/packages/flutter_tools/gradle/flutter.gradle
index 66530cb..c06edba 100644
--- a/packages/flutter_tools/gradle/flutter.gradle
+++ b/packages/flutter_tools/gradle/flutter.gradle
@@ -2,7 +2,6 @@
import java.nio.file.Paths
import com.android.builder.model.AndroidProject
-import com.android.build.OutputFile
import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
@@ -37,49 +36,6 @@
apply plugin: FlutterPlugin
class FlutterPlugin implements Plugin<Project> {
- // The platforms that can be passed to the `--Ptarget-platform` flag.
- private static final String PLATFORM_ARM32 = "android-arm";
- private static final String PLATFORM_ARM64 = "android-arm64";
- private static final String PLATFORM_X86 = "android-x86";
- private static final String PLATFORM_X86_64 = "android-x64";
-
- // The ABI architectures.
- private static final String ARCH_ARM32 = "armeabi-v7a";
- private static final String ARCH_ARM64 = "arm64-v8a";
- private static final String ARCH_X86 = "x86";
- private static final String ARCH_X86_64 = "x86_64";
-
- // Maps platforms to ABI architectures.
- private static final Map PLATFORM_ARCH_MAP = [
- (PLATFORM_ARM32) : ARCH_ARM32,
- (PLATFORM_ARM64) : ARCH_ARM64,
- (PLATFORM_X86) : ARCH_X86,
- (PLATFORM_X86_64) : ARCH_X86_64,
- ]
-
- // The version code that gives each ABI a value.
- // For each APK variant, use the following versions to override the version of the Universal APK.
- // Otherwise, the Play Store will complain that the APK variants have the same version.
- private static final Map ABI_VERSION = [
- (ARCH_ARM32) : 1,
- (ARCH_ARM64) : 2,
- (ARCH_X86) : 3,
- (ARCH_X86_64) : 4,
- ]
-
- // When split is enabled, multiple APKs are generated per each ABI.
- private static final List DEFAULT_PLATFORMS = [
- PLATFORM_ARM32,
- PLATFORM_ARM64,
- ]
-
- // The name prefix for flutter builds. This is used to identify gradle tasks
- // where we expect the flutter tool to provide any error output, and skip the
- // standard Gradle error output in the FlutterEventLogger. If you change this,
- // be sure to change any instances of this string in symbols in the code below
- // to match.
- static final String FLUTTER_BUILD_PREFIX = "flutterBuild"
-
private Path baseEnginePath
private File flutterRoot
private File flutterExecutable
@@ -93,6 +49,29 @@
private File dynamicProfileFlutterJar
private File dynamicReleaseFlutterJar
+ // The name prefix for flutter builds. This is used to identify gradle tasks
+ // where we expect the flutter tool to provide any error output, and skip the
+ // standard Gradle error output in the FlutterEventLogger. If you change this,
+ // be sure to change any instances of this string in symbols in the code below
+ // to match.
+ static final String flutterBuildPrefix = "flutterBuild"
+
+ // The platforms (or CPU architectures) for which native code is generated.
+ static final Map allTargetPlatforms = [
+ 'android-arm': 'armeabi-v7a',
+ 'android-arm64': 'arm64-v8a',
+ 'android-x64': 'x86_64',
+ 'android-x86': 'x86',
+ ]
+
+ // Supports ARM 32 and 64 bits.
+ // When splits are enabled, multiple APKs are generated per each CPU architecture,
+ // which helps decrease the size of each APK.
+ static final Set allArmPlatforms = [
+ 'android-arm',
+ 'android-arm64'
+ ]
+
private Properties readPropertiesIfExist(File propertiesFile) {
Properties result = new Properties()
if (propertiesFile.exists()) {
@@ -101,16 +80,11 @@
return result
}
- private List<String> getTargetPlatforms(Project project) {
- if (!project.hasProperty('target-platform')) {
- return DEFAULT_PLATFORMS
+ private String getTargetPlatform(Project project) {
+ if (project.hasProperty('target-platform')) {
+ return project.property('target-platform')
}
- return project.property('target-platform').split(',').collect {
- if (!PLATFORM_ARCH_MAP[it]) {
- throw new GradleException("Invalid platform: $it.")
- }
- return it
- }
+ return 'android-arm-all';
}
private Boolean getBuildShareLibrary(Project project) {
@@ -120,13 +94,6 @@
return false;
}
- private Boolean splitPerAbi(Project project) {
- if (project.hasProperty('split-per-abi')) {
- return project.property('split-per-abi').toBoolean()
- }
- return false;
- }
-
private String resolveProperty(Project project, String name, String defaultValue) {
if (localProperties == null) {
localProperties = readPropertiesIfExist(new File(project.projectDir.parentFile, "local.properties"))
@@ -144,55 +111,21 @@
return result
}
- /**
- * Returns the platform that is used to extract the `libflutter.so` and the .class files.
- *
- * Note: This is only needed to add the .class files.
- * Unfortunately, the engine artifacts include the .class and libflutter.so files.
- */
- private String getBasePlatform(Project project) {
- if (PLATFORM_ARM64 in getTargetPlatforms(project)) {
- return PLATFORM_ARM64;
- }
- return PLATFORM_ARM32;
- }
-
@Override
void apply(Project project) {
project.extensions.create("flutter", FlutterExtension)
project.afterEvaluate this.&addFlutterTask
- // By default, assembling APKs generates fat APKs if multiple platforms are passed.
- // Configuring split per ABI allows to generate separate APKs for each abi.
- // This is a noop when building a bundle.
- if (this.splitPerAbi(project)) {
- project.android {
- splits {
- abi {
- // Enables building multiple APKs per ABI.
- enable true
- // Resets the list of ABIs that Gradle should create APKs for to none.
- reset()
- // Specifies that we do not want to also generate a universal APK that includes all ABIs.
- universalApk false
- }
- }
- }
- }
- this.getTargetPlatforms(project).each { targetArch ->
- String abiValue = PLATFORM_ARCH_MAP[targetArch]
+ allTargetPlatforms.each { currentTargetPlatformValue, abi ->
project.android {
packagingOptions {
- pickFirst "lib/${abiValue}/libflutter.so"
- // Prevent the ELF library from getting corrupted.
- doNotStrip "*/${abiValue}/libapp.so"
- }
- if (this.splitPerAbi(project)) {
- splits {
- abi {
- include abiValue
- }
- }
+ pickFirst "lib/${abi}/libflutter.so"
+
+ // Disable warning by *-android-strip: File format not recognized
+ doNotStrip "*/${abi}/lib_vm_snapshot_data.so"
+ doNotStrip "*/${abi}/lib_vm_snapshot_instr.so"
+ doNotStrip "*/${abi}/lib_isolate_snapshot_data.so"
+ doNotStrip "*/${abi}/lib_isolate_snapshot_instr.so"
}
}
}
@@ -240,7 +173,7 @@
baseEnginePath = Paths.get(engineOut.absolutePath)
flutterJar = baseEnginePath.resolve("flutter.jar").toFile()
if (!flutterJar.isFile()) {
- throw new GradleException('Local engine jar not found: ' + flutterJar)
+ throw new GradleException('File not found: ' + flutterJar)
}
localEngine = engineOut.name
@@ -253,14 +186,14 @@
dynamicProfileFlutterJar = flutterJar
dynamicReleaseFlutterJar = flutterJar
} else {
- String basePlatformArch = getBasePlatform(project)
- // This is meant to include the compiled classes only, however it will include `libflutter.so` as well.
+ String targetPlatform = getTargetPlatform(project)
+ String targetArch = targetPlatform == 'android-arm64' ? 'arm64' : 'arm'
baseEnginePath = Paths.get(flutterRoot.absolutePath, "bin", "cache", "artifacts", "engine")
- debugFlutterJar = baseEnginePath.resolve("${basePlatformArch}").resolve("flutter.jar").toFile()
- profileFlutterJar = baseEnginePath.resolve("${basePlatformArch}-profile").resolve("flutter.jar").toFile()
- releaseFlutterJar = baseEnginePath.resolve("${basePlatformArch}-release").resolve("flutter.jar").toFile()
- dynamicProfileFlutterJar = baseEnginePath.resolve("${basePlatformArch}-dynamic-profile").resolve("flutter.jar").toFile()
- dynamicReleaseFlutterJar = baseEnginePath.resolve("${basePlatformArch}-dynamic-release").resolve("flutter.jar").toFile()
+ debugFlutterJar = baseEnginePath.resolve("android-${targetArch}").resolve("flutter.jar").toFile()
+ profileFlutterJar = baseEnginePath.resolve("android-${targetArch}-profile").resolve("flutter.jar").toFile()
+ releaseFlutterJar = baseEnginePath.resolve("android-${targetArch}-release").resolve("flutter.jar").toFile()
+ dynamicProfileFlutterJar = baseEnginePath.resolve("android-${targetArch}-dynamic-profile").resolve("flutter.jar").toFile()
+ dynamicReleaseFlutterJar = baseEnginePath.resolve("android-${targetArch}-dynamic-release").resolve("flutter.jar").toFile()
}
if (!debugFlutterJar.isFile()) {
@@ -276,7 +209,7 @@
// Add x86/x86_64 native library. Debug mode only, for now.
File flutterX86Jar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/flutter-x86.jar")
- Task debugX86JarTask = project.tasks.create("${FLUTTER_BUILD_PREFIX}X86Jar", Jar) {
+ Task debugX86JarTask = project.tasks.create("${flutterBuildPrefix}X86Jar", Jar) {
destinationDir flutterX86Jar.parentFile
archiveName flutterX86Jar.name
from("${flutterRoot}/bin/cache/artifacts/engine/android-x86/libflutter.so") {
@@ -288,7 +221,7 @@
}
// Add flutter.jar dependencies to all <buildType>Api configurations, including custom ones
// added after applying the Flutter plugin.
- project.android.buildTypes.each {
+ project.android.buildTypes.each {
addFlutterJarApiDependency(project, it, debugX86JarTask)
}
project.android.buildTypes.whenObjectAdded {
@@ -405,19 +338,6 @@
return "release"
}
- private static String getEngineArtifactDirName(buildType, targetArch) {
- if (buildType.name == "profile") {
- return "${targetArch}-profile"
- } else if (buildType.name == "dynamicProfile") {
- return "${targetArch}-dynamic-profile"
- } else if (buildType.name == "dynamicRelease") {
- return "${targetArch}-dynamic-release"
- } else if (buildType.debuggable) {
- return "${targetArch}"
- }
- return "${targetArch}-release"
- }
-
private void addFlutterTask(Project project) {
if (project.state.failure) {
return
@@ -475,24 +395,13 @@
extraGenSnapshotOptionsValue = project.property('extra-gen-snapshot-options')
}
- def targetPlatforms = this.getTargetPlatforms(project)
- def addFlutterDeps = { variant ->
- if (this.splitPerAbi(project)) {
- variant.outputs.each { output ->
- // Assigns the new version code to versionCodeOverride, which changes the version code
- // for only the output APK, not for the variant itself. Skipping this step simply
- // causes Gradle to use the value of variant.versionCode for the APK.
- // For more, see https://developer.android.com/studio/build/configure-apk-splits
- def abiVersionCode = ABI_VERSION.get(output.getFilter(OutputFile.ABI))
- if (abiVersionCode != null) {
- output.versionCodeOverride =
- abiVersionCode * 1000 + variant.versionCode
- }
- }
- }
+ Boolean buildSharedLibraryValue = this.getBuildShareLibrary(project)
+ String targetPlatformValue = this.getTargetPlatform(project)
+ def addFlutterDeps = { variant ->
String flutterBuildMode = buildModeFor(variant.buildType)
- if (flutterBuildMode == 'debug' && project.tasks.findByName("${FLUTTER_BUILD_PREFIX}X86Jar")) {
+
+ if (flutterBuildMode == 'debug' && project.tasks.findByName('${flutterBuildPrefix}X86Jar')) {
Task task = project.tasks.findByName("compile${variant.name.capitalize()}JavaWithJavac")
if (task) {
task.dependsOn project.flutterBuildX86Jar
@@ -504,10 +413,22 @@
}
def flutterTasks = []
- targetPlatforms.each { targetArch ->
- String abiValue = PLATFORM_ARCH_MAP[targetArch]
- String taskName = "compile${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}${targetArch.replace('android-', '').capitalize()}"
- FlutterTask compileTask = project.tasks.create(name: taskName, type: FlutterTask) {
+ def targetPlatforms = []
+
+ if (targetPlatformValue == 'android-arm-all') {
+ if (flutterBuildMode == 'release') {
+ targetPlatforms.addAll(allArmPlatforms)
+ } else {
+ targetPlatforms.add('android-arm')
+ }
+ } else {
+ targetPlatforms.add(targetPlatformValue)
+ }
+
+ targetPlatforms.each { currentTargetPlatformValue ->
+ String abiValue = allTargetPlatforms[currentTargetPlatformValue]
+ FlutterTask compileTask = project.tasks.create(name: "compile${flutterBuildPrefix}${variant.name.capitalize()}${currentTargetPlatformValue}",
+ type: FlutterTask) {
flutterRoot this.flutterRoot
flutterExecutable this.flutterExecutable
buildMode flutterBuildMode
@@ -523,53 +444,56 @@
createPatch createPatchValue
buildNumber buildNumberValue
baselineDir baselineDirValue
- targetPlatform targetArch
+ buildSharedLibrary buildSharedLibraryValue
+ targetPlatform currentTargetPlatformValue
sourceDir project.file(project.flutter.source)
- intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/${targetArch}")
+ intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/${currentTargetPlatformValue}")
extraFrontEndOptions extraFrontEndOptionsValue
extraGenSnapshotOptions extraGenSnapshotOptionsValue
}
flutterTasks.add(compileTask)
}
- def libJar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/libs.jar")
- Task packFlutterSnapshotsAndLibsTask = project.tasks.create(name: "packLibs${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}", type: Jar) {
+
+ def libJar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/libs.jar")
+ Task packFlutterSnapshotsAndLibsTask = project.tasks.create(name: "packFlutterSnapshotsAndLibs${flutterBuildPrefix}${variant.name.capitalize()}", type: Jar) {
destinationDir libJar.parentFile
archiveName libJar.name
- targetPlatforms.each { targetArch ->
- // This check prevents including `libflutter.so` twice, since it's included in the base platform jar.
- // Unfortunately, the `pickFirst` setting in `packagingOptions` does not work when the project `:flutter`
- // is included as an implementation dependency, which causes duplicated `libflutter.so`.
- if (getBasePlatform(project) != targetArch) {
- def engineArtifactSubdir = getEngineArtifactDirName(variant.buildType, targetArch);
- // Include `libflutter.so`.
- // TODO(blasten): The libs should be outside `flutter.jar` when the artifacts are downloaded.
- from(project.zipTree("${flutterRoot}/bin/cache/artifacts/engine/${engineArtifactSubdir}/flutter.jar")) {
- include 'lib/**'
- }
+ targetPlatforms.each { targetPlatform ->
+ // Include `libflutter.so` for each abi.
+ // TODO(blasten): The libs should be outside `flutter.jar` when the artifacts are downloaded.
+ from(project.zipTree("${flutterRoot}/bin/cache/artifacts/engine/${targetPlatform}-release/flutter.jar")) {
+ include 'lib/**'
}
}
+
dependsOn flutterTasks
- // Add the ELF library.
- flutterTasks.each { flutterTask ->
+ // Add the snapshots and rename them as `lib/{abi}/*.so`.
+ flutterTasks.each { flutterTask ->
from(flutterTask.intermediateDir) {
- include '*.so'
- rename { String filename ->
- return "lib/${flutterTask.abi}/lib${filename}"
+ include 'vm_snapshot_data'
+ include 'vm_snapshot_instr'
+ include 'isolate_snapshot_data'
+ include 'isolate_snapshot_instr'
+ rename { String filename ->
+ return "lib/${flutterTask.abi}/lib_${filename}.so"
}
}
}
}
+
// Include the snapshots and libflutter.so in `lib/`.
- project.dependencies {
- String configuration;
- if (project.getConfigurations().findByName("api")) {
- configuration = buildType.name + "Api";
- } else {
- configuration = buildType.name + "Compile";
+ if (flutterBuildMode == 'release' && targetPlatformValue == 'android-arm-all') {
+ project.dependencies {
+ String configuration;
+ if (project.getConfigurations().findByName("api")) {
+ configuration = buildType.name + "Api";
+ } else {
+ configuration = buildType.name + "Compile";
+ }
+ add(configuration, project.files {
+ packFlutterSnapshotsAndLibsTask
+ })
}
- add(configuration, project.files {
- packFlutterSnapshotsAndLibsTask
- })
}
// We know that the flutter app is a subproject in another Android app when these tasks exist.
Task packageAssets = project.tasks.findByPath(":flutter:package${variant.name.capitalize()}Assets")
@@ -586,8 +510,12 @@
variant.mergeAssets.mustRunAfter("clean${variant.mergeAssets.name.capitalize()}")
into variant.mergeAssets.outputDir
}
- flutterTasks.each { flutterTask ->
+ flutterTasks.each { flutterTask ->
with flutterTask.assets
+ // Include the snapshots in the assets directory.
+ if (flutterBuildMode != 'release' || targetPlatformValue != 'android-arm-all') {
+ with flutterTask.snapshots
+ }
}
}
if (packageAssets) {
@@ -648,6 +576,8 @@
@Optional @Input
String baselineDir
@Optional @Input
+ Boolean buildSharedLibrary
+ @Optional @Input
String targetPlatform
@Input
String abi
@@ -692,10 +622,8 @@
args "build", "aot"
args "--suppress-analytics"
args "--quiet"
- args "--build-shared-library"
args "--target", targetPath
args "--output-dir", "${intermediateDir}"
- args "--target-platform", "${targetPlatform}"
if (trackWidgetCreation) {
args "--track-widget-creation"
}
@@ -705,6 +633,14 @@
if (extraGenSnapshotOptions != null) {
args "--extra-gen-snapshot-options", "${extraGenSnapshotOptions}"
}
+ if (buildSharedLibrary) {
+ args "--build-shared-library"
+ }
+ if (targetPlatform == null) {
+ args "--target-platform", "android-arm"
+ } else {
+ args "--target-platform", "${targetPlatform}"
+ }
args "--${buildMode}"
}
}
@@ -719,7 +655,6 @@
args "build", "bundle"
args "--suppress-analytics"
args "--target", targetPath
- args "--target-platform", "${targetPlatform}"
if (verbose) {
args "--verbose"
}
@@ -753,6 +688,9 @@
if (extraGenSnapshotOptions != null) {
args "--extra-gen-snapshot-options", "${extraGenSnapshotOptions}"
}
+ if (targetPlatform != null) {
+ args "--target-platform", "${targetPlatform}"
+ }
if (buildMode == "release" || buildMode == "profile") {
args "--precompiled"
} else {
@@ -793,7 +731,14 @@
from "${intermediateDir}"
if (buildMode == 'release' || buildMode == 'profile') {
- include "app.so"
+ if (buildSharedLibrary) {
+ include "app.so"
+ } else {
+ include "vm_snapshot_data"
+ include "vm_snapshot_instr"
+ include "isolate_snapshot_data"
+ include "isolate_snapshot_instr"
+ }
}
}
}
@@ -860,7 +805,7 @@
void buildFinished(BuildResult result) {
if (result.failure != null) {
- if (!(result.failure instanceof GradleException) || !mostRecentTask.startsWith(FlutterPlugin.FLUTTER_BUILD_PREFIX)) {
+ if (!(result.failure instanceof GradleException) || !mostRecentTask.startsWith(FlutterPlugin.flutterBuildPrefix)) {
result.rethrowFailure()
}
}
diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index f215124..e062da5 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -388,27 +388,18 @@
if (!await _checkForSupportedAdbVersion() || !await _checkForSupportedAndroidVersion())
return LaunchResult.failed();
-
- if (!debuggingOptions.buildInfo.isDebug &&
- !debuggingOptions.buildInfo.isDynamic) {
- printError('Profile and release builds are only supported.');
+ final TargetPlatform devicePlatform = await targetPlatform;
+ if (!(devicePlatform == TargetPlatform.android_arm ||
+ devicePlatform == TargetPlatform.android_arm64) &&
+ !(debuggingOptions.buildInfo.isDebug ||
+ debuggingOptions.buildInfo.isDynamic)) {
+ printError('Profile and release builds are only supported on ARM targets.');
return LaunchResult.failed();
}
- final TargetPlatform devicePlatform = await targetPlatform;
-
- AndroidArch androidArch;
- switch (devicePlatform) {
- case TargetPlatform.android_arm:
- androidArch = AndroidArch.armeabi_v7a;
- break;
- case TargetPlatform.android_arm64:
- androidArch = AndroidArch.arm64_v8a;
- break;
- default:
- printError('ARM targets are only supported.');
- return LaunchResult.failed();
- }
+ BuildInfo buildInfo = debuggingOptions.buildInfo;
+ if (buildInfo.targetPlatform == null && devicePlatform == TargetPlatform.android_arm64)
+ buildInfo = buildInfo.withTargetPlatform(TargetPlatform.android_arm64);
if (!prebuiltApplication || androidSdk.licensesAvailable && androidSdk.latestVersion == null) {
printTrace('Building APK');
@@ -416,9 +407,7 @@
await buildApk(
project: project,
target: mainPath,
- androidBuildInfo: AndroidBuildInfo(debuggingOptions.buildInfo,
- targetArchs: <AndroidArch>[androidArch]
- ),
+ buildInfo: buildInfo,
);
// 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 908c535..8b5b8d9 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,
- @required AndroidBuildInfo androidBuildInfo,
+ BuildInfo buildInfo = BuildInfo.debug,
}) async {
if (!project.android.isUsingGradle) {
throwToolExit(
@@ -33,7 +33,7 @@
await buildGradleProject(
project: project,
- androidBuildInfo: androidBuildInfo,
+ buildInfo: buildInfo,
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 4f304c1..c1e94ab 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,
- @required AndroidBuildInfo androidBuildInfo,
+ BuildInfo buildInfo = BuildInfo.debug,
}) async {
if (!project.android.isUsingGradle) {
throwToolExit(
@@ -42,7 +42,7 @@
return buildGradleProject(
project: project,
- androidBuildInfo: androidBuildInfo,
+ buildInfo: buildInfo,
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 bf53166..62f4475 100644
--- a/packages/flutter_tools/lib/src/android/gradle.dart
+++ b/packages/flutter_tools/lib/src/android/gradle.dart
@@ -15,7 +15,6 @@
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';
@@ -319,7 +318,7 @@
Future<void> buildGradleProject({
@required FlutterProject project,
- @required AndroidBuildInfo androidBuildInfo,
+ @required BuildInfo buildInfo,
@required String target,
@required bool isBuildingBundle,
}) async {
@@ -331,7 +330,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: androidBuildInfo.buildInfo);
+ updateLocalProperties(project: project, buildInfo: buildInfo);
final String gradle = await _ensureGradle(project);
@@ -343,7 +342,7 @@
case FlutterPluginVersion.managed:
// Fall through. Managed plugin builds the same way as plugin v2.
case FlutterPluginVersion.v2:
- return _buildGradleProjectV2(project, gradle, androidBuildInfo, target, isBuildingBundle);
+ return _buildGradleProjectV2(project, gradle, buildInfo, target, isBuildingBundle);
}
}
@@ -392,12 +391,11 @@
Future<void> _buildGradleProjectV2(
FlutterProject flutterProject,
String gradle,
- AndroidBuildInfo androidBuildInfo,
+ BuildInfo buildInfo,
String target,
bool isBuildingBundle,
) async {
final GradleProject project = await _gradleProject();
- final BuildInfo buildInfo = androidBuildInfo.buildInfo;
String assembleTask;
@@ -455,13 +453,12 @@
command.add('-Pfilesystem-roots=${buildInfo.fileSystemRoots.join('|')}');
if (buildInfo.fileSystemScheme != null)
command.add('-Pfilesystem-scheme=${buildInfo.fileSystemScheme}');
- 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.buildSharedLibrary) {
+ command.add('-Pbuild-shared-library=true');
}
+ if (buildInfo.targetPlatform != null)
+ command.add('-Ptarget-platform=${getNameForTargetPlatform(buildInfo.targetPlatform)}');
+
command.add(assembleTask);
bool potentialAndroidXFailure = false;
final Stopwatch sw = Stopwatch()..start();
@@ -511,27 +508,24 @@
flutterUsage.sendTiming('build', 'gradle-v2', Duration(milliseconds: sw.elapsedMilliseconds));
if (!isBuildingBundle) {
- final Iterable<File> apkFiles = _findApkFiles(project, androidBuildInfo);
- if (apkFiles.isEmpty)
+ final File apkFile = _findApkFile(project, buildInfo);
+ if (apkFile == null)
throwToolExit('Gradle build failed to produce an Android package.');
- // 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);
+ // Copy the APK to app.apk, so `flutter run`, `flutter install`, etc. can find it.
+ apkFile.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(apkFiles.first));
+ apkShaFile.writeAsStringSync(_calculateSha(apkFile));
- 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);
+ String appSize;
+ if (buildInfo.mode == BuildMode.debug) {
+ appSize = '';
+ } else {
+ appSize = ' (${getSizeAsMB(apkFile.lengthSync())})';
}
+ printStatus('Built ${fs.path.relative(apkFile.path)}$appSize.');
+
} else {
final File bundleFile = _findBundleFile(project, buildInfo);
if (bundleFile == null)
@@ -543,38 +537,28 @@
} else {
appSize = ' (${getSizeAsMB(bundleFile.lengthSync())})';
}
- printStatus('Built ${fs.path.relative(bundleFile.path)}$appSize.',
- color: TerminalColor.green);
+ printStatus('Built ${fs.path.relative(bundleFile.path)}$appSize.');
}
}
-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;
- 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;
- }
+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));
+ if (apkFile.existsSync())
+ return apkFile;
+ }
+ return null;
}
File _findBundleFile(GradleProject project, BuildInfo buildInfo) {
@@ -583,12 +567,12 @@
if (bundleFileName == null)
return null;
final String modeName = camelCase(buildInfo.modeName);
- File bundleFile = project.bundleDirectory.childDirectory(modeName).childFile(bundleFileName);
+ File bundleFile = fs.file(fs.path.join(project.bundleDirectory.path, modeName, 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 = project.bundleDirectory.childDirectory(buildInfo.flavor + modeName).childFile(bundleFileName);
+ bundleFile = fs.file(fs.path.join(project.bundleDirectory.path, buildInfo.flavor + modeName, bundleFileName));
if (bundleFile.existsSync())
return bundleFile;
}
@@ -677,20 +661,13 @@
return 'assemble${toTitleCase(productFlavor)}${toTitleCase(buildType)}';
}
- Iterable<String> apkFilesFor(AndroidBuildInfo androidBuildInfo) {
- final String buildType = _buildTypeFor(androidBuildInfo.buildInfo);
- final String productFlavor = _productFlavorFor(androidBuildInfo.buildInfo);
+ String apkFileFor(BuildInfo buildInfo) {
+ final String buildType = _buildTypeFor(buildInfo);
+ final String productFlavor = _productFlavorFor(buildInfo);
if (buildType == null || productFlavor == null)
- return const <String>[];
-
+ return null;
final String flavorString = productFlavor.isEmpty ? '' : '-' + productFlavor;
- 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'];
+ return '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 1908cb3..4b46edb 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('--elf=$aotSharedLibrary');
+ genSnapshotArgs.add('--assembly=$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 e346019..8379e81 100644
--- a/packages/flutter_tools/lib/src/build_info.dart
+++ b/packages/flutter_tools/lib/src/build_info.dart
@@ -17,6 +17,8 @@
this.compilationTraceFilePath,
this.extraFrontEndOptions,
this.extraGenSnapshotOptions,
+ this.buildSharedLibrary,
+ this.targetPlatform,
this.fileSystemRoots,
this.fileSystemScheme,
this.buildNumber,
@@ -48,6 +50,12 @@
/// 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.
@@ -90,31 +98,15 @@
bool get supportsSimulator => isEmulatorBuildMode(mode);
String get modeName => getModeName(mode);
String get friendlyModeName => getFriendlyModeName(mode);
-}
-/// 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;
+ BuildInfo withTargetPlatform(TargetPlatform targetPlatform) =>
+ BuildInfo(mode, flavor,
+ trackWidgetCreation: trackWidgetCreation,
+ compilationTraceFilePath: compilationTraceFilePath,
+ extraFrontEndOptions: extraFrontEndOptions,
+ extraGenSnapshotOptions: extraGenSnapshotOptions,
+ buildSharedLibrary: buildSharedLibrary,
+ targetPlatform: targetPlatform);
}
/// The type of build.
@@ -262,13 +254,6 @@
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,
@@ -350,51 +335,6 @@
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 5d9cbe8..1d7fbff 100644
--- a/packages/flutter_tools/lib/src/commands/build_apk.dart
+++ b/packages/flutter_tools/lib/src/commands/build_apk.dart
@@ -5,9 +5,6 @@
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';
@@ -24,14 +21,12 @@
argParser
..addFlag('track-widget-creation', negatable: false, hide: !verboseHelp)
- ..addFlag('split-per-abi',
+ ..addFlag('build-shared-library',
negatable: false,
- help: 'Whether to split the APKs per ABIs.'
- 'To learn more, see: https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split',
+ help: 'Whether to prefer compiling to a *.so file (android only).',
)
- ..addMultiOption('target-platform',
- splitCommas: true,
- defaultsTo: <String>['android-arm', 'android-arm64'],
+ ..addOption('target-platform',
+ defaultsTo: 'android-arm',
allowed: <String>['android-arm', 'android-arm64', 'android-x86', 'android-x64'],
help: 'The target platform for which the app is compiled.',
);
@@ -54,33 +49,10 @@
@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,
- androidBuildInfo: androidBuildInfo,
+ buildInfo: getBuildInfo(),
);
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 76c5ad1..dcc9d4a 100644
--- a/packages/flutter_tools/lib/src/commands/build_appbundle.dart
+++ b/packages/flutter_tools/lib/src/commands/build_appbundle.dart
@@ -5,7 +5,6 @@
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';
@@ -21,11 +20,18 @@
argParser
..addFlag('track-widget-creation', negatable: false, hide: !verboseHelp)
- ..addMultiOption('target-platform',
- splitCommas: true,
- defaultsTo: <String>['android-arm', 'android-arm64'],
+ ..addFlag(
+ 'build-shared-library',
+ negatable: false,
+ help: 'Whether to prefer compiling to a *.so file (android only).',
+ )
+ ..addOption(
+ 'target-platform',
allowed: <String>['android-arm', 'android-arm64'],
- help: 'The target platform for which the app is compiled.',
+ 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',
);
}
@@ -41,13 +47,10 @@
@override
Future<FlutterCommandResult> runCommand() async {
- final AndroidBuildInfo androidBuildInfo = AndroidBuildInfo(getBuildInfo(),
- targetArchs: argResults['target-platform'].map<AndroidArch>(getAndroidArchForName)
- );
await buildAppBundle(
project: FlutterProject.current(),
target: targetFile,
- androidBuildInfo: androidBuildInfo,
+ buildInfo: getBuildInfo(),
);
return null;
}
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index 62535d0..9f36386 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -387,7 +387,8 @@
final BuildInfo debugBuildInfo = BuildInfo(BuildMode.debug, buildInfo.flavor,
trackWidgetCreation: buildInfo.trackWidgetCreation,
extraFrontEndOptions: buildInfo.extraFrontEndOptions,
- extraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions);
+ extraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions,
+ buildSharedLibrary: buildInfo.buildSharedLibrary);
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 634d4a8..b39e674 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -320,6 +320,12 @@
}
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;
@@ -356,6 +362,10 @@
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)
diff --git a/packages/flutter_tools/test/android/gradle_test.dart b/packages/flutter_tools/test/android/gradle_test.dart
index 7aafd64..3940e9b 100644
--- a/packages/flutter_tools/test/android/gradle_test.dart
+++ b/packages/flutter_tools/test/android/gradle_test.dart
@@ -157,102 +157,16 @@
});
test('should provide apk file name for default build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir'),fs.directory('/some/dir'));
- expect(project.apkFilesFor(const AndroidBuildInfo(BuildInfo.debug)).first, 'app-debug.apk');
- expect(project.apkFilesFor(const AndroidBuildInfo(BuildInfo.profile)).first, 'app-profile.apk');
- expect(project.apkFilesFor(const AndroidBuildInfo(BuildInfo.release)).first, 'app-release.apk');
- expect(project.apkFilesFor(const AndroidBuildInfo(BuildInfo(BuildMode.release, 'unknown'))).isEmpty, isTrue);
+ expect(project.apkFileFor(BuildInfo.debug), 'app-debug.apk');
+ expect(project.apkFileFor(BuildInfo.profile), 'app-profile.apk');
+ expect(project.apkFileFor(BuildInfo.release), 'app-release.apk');
+ expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
});
test('should provide apk file name for flavored build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/some/dir'),fs.directory('/some/dir'));
- expect(project.apkFilesFor(const AndroidBuildInfo(BuildInfo(BuildMode.debug, 'free'))).first, 'app-free-debug.apk');
- expect(project.apkFilesFor(const AndroidBuildInfo(BuildInfo(BuildMode.release, 'paid'))).first, 'app-paid-release.apk');
- expect(project.apkFilesFor(const AndroidBuildInfo(BuildInfo(BuildMode.release, 'unknown'))).isEmpty, isTrue);
- });
- test('should provide apks for default build types and each ABI', () {
- final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir'),fs.directory('/some/dir'));
- expect(project.apkFilesFor(
- const AndroidBuildInfo(
- BuildInfo.debug,
- splitPerAbi: true,
- targetArchs: <AndroidArch>[
- AndroidArch.armeabi_v7a,
- AndroidArch.arm64_v8a,
- ]
- )
- ),
- <String>[
- 'app-armeabi-v7a-debug.apk',
- 'app-arm64-v8a-debug.apk',
- ]);
-
- expect(project.apkFilesFor(
- const AndroidBuildInfo(
- BuildInfo.release,
- splitPerAbi: true,
- targetArchs: <AndroidArch>[
- AndroidArch.armeabi_v7a,
- AndroidArch.arm64_v8a,
- ]
- )
- ),
- <String>[
- 'app-armeabi-v7a-release.apk',
- 'app-arm64-v8a-release.apk',
- ]);
-
- expect(project.apkFilesFor(
- const AndroidBuildInfo(
- BuildInfo(BuildMode.release, 'unknown'),
- splitPerAbi: true,
- targetArchs: <AndroidArch>[
- AndroidArch.armeabi_v7a,
- AndroidArch.arm64_v8a,
- ]
- )
- ).isEmpty, isTrue);
- });
- test('should provide apks for each ABI and flavored build types', () {
- final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/some/dir'),fs.directory('/some/dir'));
- expect(project.apkFilesFor(
- const AndroidBuildInfo(
- BuildInfo(BuildMode.debug, 'free'),
- splitPerAbi: true,
- targetArchs: <AndroidArch>[
- AndroidArch.armeabi_v7a,
- AndroidArch.arm64_v8a,
- ]
- )
- ),
- <String>[
- 'app-free-armeabi-v7a-debug.apk',
- 'app-free-arm64-v8a-debug.apk',
- ]);
-
- expect(project.apkFilesFor(
- const AndroidBuildInfo(
- BuildInfo(BuildMode.release, 'paid'),
- splitPerAbi: true,
- targetArchs: <AndroidArch>[
- AndroidArch.armeabi_v7a,
- AndroidArch.arm64_v8a,
- ]
- )
- ),
- <String>[
- 'app-paid-armeabi-v7a-release.apk',
- 'app-paid-arm64-v8a-release.apk',
- ]);
-
- expect(project.apkFilesFor(
- const AndroidBuildInfo(
- BuildInfo(BuildMode.release, 'unknown'),
- splitPerAbi: true,
- targetArchs: <AndroidArch>[
- AndroidArch.armeabi_v7a,
- AndroidArch.arm64_v8a,
- ]
- )
- ).isEmpty, isTrue);
+ expect(project.apkFileFor(const BuildInfo(BuildMode.debug, 'free')), 'app-free-debug.apk');
+ expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'paid')), 'app-paid-release.apk');
+ expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
});
test('should provide bundle file name for default build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir'),fs.directory('/some/dir'));
diff --git a/packages/flutter_tools/test/base/build_test.dart b/packages/flutter_tools/test/base/build_test.dart
index 8c32fd9..60d3724 100644
--- a/packages/flutter_tools/test/base/build_test.dart
+++ b/packages/flutter_tools/test/base/build_test.dart
@@ -80,7 +80,7 @@
});
});
- group('Snapshotter - AOT', () {
+ group('Snapshotter - iOS AOT', () {
const String kSnapshotDart = 'snapshot.dart';
String skyEnginePath;
@@ -395,11 +395,10 @@
]);
}, overrides: contextOverrides);
- testUsingContext('builds shared library for android-arm', () async {
- fs.file('main.dill').writeAsStringSync('binary magic');
-
+ testUsingContext('returns failure if buildSharedLibrary is true but no NDK is found', () async {
final String outputPath = fs.path.join('build', 'foo');
- fs.directory(outputPath).createSync(recursive: true);
+
+ when(mockAndroidSdk.ndk).thenReturn(null);
final int genSnapshotExitCode = await snapshotter.build(
platform: TargetPlatform.android_arm,
@@ -410,45 +409,8 @@
buildSharedLibrary: true,
);
- expect(genSnapshotExitCode, 0);
- expect(genSnapshot.callCount, 1);
- expect(genSnapshot.snapshotType.platform, TargetPlatform.android_arm);
- expect(genSnapshot.snapshotType.mode, BuildMode.release);
- expect(genSnapshot.additionalArgs, <String>[
- '--deterministic',
- '--snapshot_kind=app-aot-elf',
- '--elf=build/foo/app.so',
- '--no-sim-use-hardfp',
- '--no-use-integer-division',
- 'main.dill',
- ]);
- }, overrides: contextOverrides);
-
- testUsingContext('builds shared library for android-arm64', () async {
- fs.file('main.dill').writeAsStringSync('binary magic');
-
- final String outputPath = fs.path.join('build', 'foo');
- fs.directory(outputPath).createSync(recursive: true);
-
- final int genSnapshotExitCode = await snapshotter.build(
- platform: TargetPlatform.android_arm64,
- buildMode: BuildMode.release,
- mainPath: 'main.dill',
- packagesPath: '.packages',
- outputPath: outputPath,
- buildSharedLibrary: true,
- );
-
- expect(genSnapshotExitCode, 0);
- expect(genSnapshot.callCount, 1);
- expect(genSnapshot.snapshotType.platform, TargetPlatform.android_arm64);
- expect(genSnapshot.snapshotType.mode, BuildMode.release);
- expect(genSnapshot.additionalArgs, <String>[
- '--deterministic',
- '--snapshot_kind=app-aot-elf',
- '--elf=build/foo/app.so',
- 'main.dill',
- ]);
+ expect(genSnapshotExitCode, isNot(0));
+ expect(genSnapshot.callCount, 0);
}, overrides: contextOverrides);
testUsingContext('builds Android arm release AOT snapshot', () async {
diff --git a/packages/flutter_tools/test/ios/xcodeproj_test.dart b/packages/flutter_tools/test/ios/xcodeproj_test.dart
index 6a42162..63685c5 100644
--- a/packages/flutter_tools/test/ios/xcodeproj_test.dart
+++ b/packages/flutter_tools/test/ios/xcodeproj_test.dart
@@ -286,7 +286,7 @@
platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
- const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null);
+ const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null, targetPlatform: TargetPlatform.ios);
final FlutterProject project = FlutterProject.fromPath('path/to/project');
await updateGeneratedXcodeProperties(
project: project,
@@ -304,7 +304,7 @@
when(mockArtifacts.getArtifactPath(Artifact.flutterFramework,
platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
- const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null, trackWidgetCreation: true);
+ const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null, trackWidgetCreation: true, targetPlatform: TargetPlatform.ios);
final FlutterProject project = FlutterProject.fromPath('path/to/project');
await updateGeneratedXcodeProperties(
project: project,
@@ -322,7 +322,7 @@
when(mockArtifacts.getArtifactPath(Artifact.flutterFramework,
platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile_arm'));
- const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null);
+ const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null, targetPlatform: TargetPlatform.ios);
final FlutterProject project = FlutterProject.fromPath('path/to/project');
await updateGeneratedXcodeProperties(
project: project,
@@ -340,7 +340,7 @@
when(mockArtifacts.getArtifactPath(Artifact.flutterFramework,
platform: TargetPlatform.ios, mode: anyNamed('mode'))).thenReturn('engine');
when(mockArtifacts.engineOutPath).thenReturn(fs.path.join('out', 'ios_profile'));
- const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null);
+ const BuildInfo buildInfo = BuildInfo(BuildMode.debug, null, targetPlatform: TargetPlatform.ios);
final FlutterProject project = FlutterProject.fromPath('path/to/project');
await updateGeneratedXcodeProperties(