mirror of
https://github.com/flutter/flutter
synced 2024-09-19 16:21:58 +00:00
Revert "Generate ELF shared libraries and allow multi-abi libs in APKs and App bundles (#33696)" (#34121)
This commit is contained in:
parent
966b15b4a4
commit
f8f7b89976
|
@ -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 @@ Future<void> main() async {
|
|||
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 @@ Future<void> main() async {
|
|||
'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 @@ Future<void> main() async {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
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 @@ class FlutterPluginProject {
|
|||
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 {
|
||||
|
|
|
@ -5,7 +5,7 @@ homepage: https://github.com/flutter/flutter
|
|||
|
||||
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
|
||||
|
|
|
@ -2,7 +2,6 @@ import java.nio.file.Path
|
|||
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 @@ android {
|
|||
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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
return result
|
||||
}
|
||||
|
||||
private List<String> getTargetPlatforms(Project project) {
|
||||
if (!project.hasProperty('target-platform')) {
|
||||
return DEFAULT_PLATFORMS
|
||||
}
|
||||
return project.property('target-platform').split(',').collect {
|
||||
if (!PLATFORM_ARCH_MAP[it]) {
|
||||
throw new GradleException("Invalid platform: $it.")
|
||||
}
|
||||
return it
|
||||
private String getTargetPlatform(Project project) {
|
||||
if (project.hasProperty('target-platform')) {
|
||||
return project.property('target-platform')
|
||||
}
|
||||
return 'android-arm-all';
|
||||
}
|
||||
|
||||
private Boolean getBuildShareLibrary(Project project) {
|
||||
|
@ -120,13 +94,6 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
|
||||
// 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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
}
|
||||
// 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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
}
|
||||
|
||||
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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
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 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
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 @@ abstract class BaseFlutterTask extends DefaultTask {
|
|||
@Optional @Input
|
||||
String baselineDir
|
||||
@Optional @Input
|
||||
Boolean buildSharedLibrary
|
||||
@Optional @Input
|
||||
String targetPlatform
|
||||
@Input
|
||||
String abi
|
||||
|
@ -692,10 +622,8 @@ abstract class BaseFlutterTask extends DefaultTask {
|
|||
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 @@ abstract class BaseFlutterTask extends DefaultTask {
|
|||
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 @@ abstract class BaseFlutterTask extends DefaultTask {
|
|||
args "build", "bundle"
|
||||
args "--suppress-analytics"
|
||||
args "--target", targetPath
|
||||
args "--target-platform", "${targetPlatform}"
|
||||
if (verbose) {
|
||||
args "--verbose"
|
||||
}
|
||||
|
@ -753,6 +688,9 @@ abstract class BaseFlutterTask extends DefaultTask {
|
|||
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 @@ class FlutterTask extends BaseFlutterTask {
|
|||
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 @@ class FlutterEventLogger extends BuildAdapter implements TaskExecutionListener {
|
|||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -388,27 +388,18 @@ class AndroidDevice extends Device {
|
|||
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 @@ class AndroidDevice extends Device {
|
|||
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.
|
||||
|
|
|
@ -16,7 +16,7 @@ import 'gradle.dart';
|
|||
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 @@ Future<void> buildApk({
|
|||
|
||||
await buildGradleProject(
|
||||
project: project,
|
||||
androidBuildInfo: androidBuildInfo,
|
||||
buildInfo: buildInfo,
|
||||
target: target,
|
||||
isBuildingBundle: false,
|
||||
);
|
||||
|
|
|
@ -17,7 +17,7 @@ import 'gradle.dart';
|
|||
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 @@ Future<void> buildAppBundle({
|
|||
|
||||
return buildGradleProject(
|
||||
project: project,
|
||||
androidBuildInfo: androidBuildInfo,
|
||||
buildInfo: buildInfo,
|
||||
target: target,
|
||||
isBuildingBundle: true,
|
||||
);
|
||||
|
|
|
@ -15,7 +15,6 @@ import '../base/logger.dart';
|
|||
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 @@ void _exitIfNoAndroidSdk() {
|
|||
|
||||
Future<void> buildGradleProject({
|
||||
@required FlutterProject project,
|
||||
@required AndroidBuildInfo androidBuildInfo,
|
||||
@required BuildInfo buildInfo,
|
||||
@required String target,
|
||||
@required bool isBuildingBundle,
|
||||
}) async {
|
||||
|
@ -331,7 +330,7 @@ Future<void> buildGradleProject({
|
|||
// 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 @@ Future<void> buildGradleProject({
|
|||
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 @@ String _calculateSha(File file) {
|
|||
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 @@ Future<void> _buildGradleProjectV2(
|
|||
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 @@ Future<void> _buildGradleProjectV2(
|
|||
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 @@ Future<void> _buildGradleProjectV2(
|
|||
} 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 @@ File _findBundleFile(GradleProject project, BuildInfo buildInfo) {
|
|||
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 @@ class GradleProject {
|
|||
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) {
|
||||
|
|
|
@ -137,7 +137,7 @@ class AOTSnapshotter {
|
|||
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');
|
||||
|
|
|
@ -17,6 +17,8 @@ class BuildInfo {
|
|||
this.compilationTraceFilePath,
|
||||
this.extraFrontEndOptions,
|
||||
this.extraGenSnapshotOptions,
|
||||
this.buildSharedLibrary,
|
||||
this.targetPlatform,
|
||||
this.fileSystemRoots,
|
||||
this.fileSystemScheme,
|
||||
this.buildNumber,
|
||||
|
@ -48,6 +50,12 @@ class BuildInfo {
|
|||
/// 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 @@ class BuildInfo {
|
|||
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 @@ enum IOSArch {
|
|||
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 @@ TargetPlatform getTargetPlatformForName(String platform) {
|
|||
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;
|
||||
|
|
|
@ -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 @@ class BuildApkCommand extends BuildSubCommand {
|
|||
|
||||
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 @@ class BuildApkCommand extends BuildSubCommand {
|
|||
|
||||
@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;
|
||||
}
|
||||
|
|
|
@ -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 @@ class BuildAppBundleCommand extends BuildSubCommand {
|
|||
|
||||
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 @@ class BuildAppBundleCommand extends BuildSubCommand {
|
|||
|
||||
@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;
|
||||
}
|
||||
|
|
|
@ -387,7 +387,8 @@ class IOSSimulator extends Device {
|
|||
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,
|
||||
|
|
|
@ -320,6 +320,12 @@ abstract class FlutterCommand extends Command<void> {
|
|||
}
|
||||
|
||||
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 @@ abstract class FlutterCommand extends Command<void> {
|
|||
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)
|
||||
|
|
|
@ -157,102 +157,16 @@ someOtherTask
|
|||
});
|
||||
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'));
|
||||
|
|
|
@ -80,7 +80,7 @@ void main() {
|
|||
});
|
||||
});
|
||||
|
||||
group('Snapshotter - AOT', () {
|
||||
group('Snapshotter - iOS AOT', () {
|
||||
const String kSnapshotDart = 'snapshot.dart';
|
||||
String skyEnginePath;
|
||||
|
||||
|
@ -395,11 +395,10 @@ void main() {
|
|||
]);
|
||||
}, 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 @@ void main() {
|
|||
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 {
|
||||
|
|
|
@ -286,7 +286,7 @@ Information about project "Runner":
|
|||
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 @@ Information about project "Runner":
|
|||
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 @@ Information about project "Runner":
|
|||
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 @@ Information about project "Runner":
|
|||
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(
|
||||
|
|
Loading…
Reference in a new issue