Unverified Commit 1d2eaaf2 authored by Emmanuel Garcia's avatar Emmanuel Garcia Committed by GitHub

Ensure that flutter assets are copied in the AAR (#42306)

parent a3c750a2
......@@ -956,6 +956,7 @@ Future<void> _androidGradleTests(String subShard) async {
await _runDevicelabTest('gradle_plugin_bundle_test', env: env);
await _runDevicelabTest('module_test', env: env);
await _runDevicelabTest('module_host_with_custom_build_test', env: env);
await _runDevicelabTest('build_aar_module_test', env: env);
}
}
......
......@@ -80,7 +80,7 @@ Future<void> main() async {
'flutter_release-1.0.aar',
));
checkFileExists(path.join(
final String releasePom = path.join(
repoPath,
'io',
'flutter',
......@@ -89,55 +89,29 @@ Future<void> main() async {
'flutter_release',
'1.0',
'flutter_release-1.0.pom',
));
checkFileExists(path.join(
repoPath,
'io',
'flutter',
'plugins',
'deviceinfo',
'device_info_release',
'1.0',
'device_info_release-1.0.aar',
));
);
checkFileExists(path.join(
repoPath,
'io',
'flutter',
'plugins',
'deviceinfo',
'device_info_release',
'1.0',
'device_info_release-1.0.pom',
));
checkFileExists(releasePom);
checkFileExists(path.join(
repoPath,
'io',
'flutter',
'plugins',
'packageinfo',
'package_info_release',
'1.0',
'package_info_release-1.0.aar',
));
section('Check AOT blobs in release POM');
checkFileExists(path.join(
repoPath,
'io',
'flutter',
'plugins',
'packageinfo',
'package_info_release',
'1.0',
'package_info_release-1.0.pom',
));
checkFileContains(<String>[
'flutter_embedding_release',
'armeabi_v7a_release',
'arm64_v8a_release',
], releasePom);
section('Check assets in release AAR');
final Iterable<String> releaseAar = await getFilesInAar(path.join(
checkItContains<String>(
<String>[
...flutterAssets,
// AOT snapshots
'jni/arm64-v8a/libapp.so',
'jni/armeabi-v7a/libapp.so',
],
await getFilesInAar(
path.join(
repoPath,
'io',
'flutter',
......@@ -146,21 +120,9 @@ Future<void> main() async {
'flutter_release',
'1.0',
'flutter_release-1.0.aar',
));
checkItContains<String>(<String>[
'assets/flutter_assets/FontManifest.json',
'assets/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf',
], releaseAar);
section('Check AOT blobs in release AAR');
checkItContains<String>(<String>[
'jni/arm64-v8a/libapp.so',
'jni/arm64-v8a/libflutter.so',
'jni/armeabi-v7a/libapp.so',
'jni/armeabi-v7a/libflutter.so',
], releaseAar);
)
)
);
section('Build debug AAR');
......@@ -182,7 +144,7 @@ Future<void> main() async {
'flutter_debug-1.0.aar',
));
checkFileExists(path.join(
final String debugPom = path.join(
repoPath,
'io',
'flutter',
......@@ -191,52 +153,19 @@ Future<void> main() async {
'flutter_debug',
'1.0',
'flutter_debug-1.0.pom',
));
checkFileExists(path.join(
repoPath,
'io',
'flutter',
'plugins',
'deviceinfo',
'device_info_debug',
'1.0',
'device_info_debug-1.0.aar',
));
checkFileExists(path.join(
repoPath,
'io',
'flutter',
'plugins',
'deviceinfo',
'device_info_debug',
'1.0',
'device_info_debug-1.0.pom',
));
);
checkFileExists(path.join(
repoPath,
'io',
'flutter',
'plugins',
'packageinfo',
'package_info_debug',
'1.0',
'package_info_debug-1.0.aar',
));
checkFileExists(debugPom);
checkFileExists(path.join(
repoPath,
'io',
'flutter',
'plugins',
'packageinfo',
'package_info_debug',
'1.0',
'package_info_debug-1.0.pom',
));
section('Check AOT blobs in debug POM');
checkFileContains(<String>[
'flutter_embedding_debug',
'x86_debug',
'x86_64_debug',
'armeabi_v7a_debug',
'arm64_v8a_debug',
], debugPom);
section('Check assets in debug AAR');
......@@ -252,23 +181,13 @@ Future<void> main() async {
));
checkItContains<String>(<String>[
'assets/flutter_assets/FontManifest.json',
'assets/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf',
...flutterAssets,
// JIT snapshots.
'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data',
], debugAar);
section('Check AOT blobs in debug AAR');
checkItContains<String>(<String>[
'jni/arm64-v8a/libflutter.so',
'jni/armeabi-v7a/libflutter.so',
'jni/x86/libflutter.so',
'jni/x86_64/libflutter.so',
], debugAar);
return TaskResult.success(null);
} on TaskResult catch (taskResult) {
return taskResult;
......
......@@ -84,6 +84,20 @@ void checkItDoesNotContain<T>(Iterable<T> values, Iterable<T> collection) {
}
}
/// Checks that [str] contains the specified [Pattern]s, otherwise throws
/// a [TaskResult].
void checkFileContains(List<Pattern> patterns, String filePath) {
final String fileContent = File(filePath).readAsStringSync();
for (Pattern pattern in patterns) {
if (!fileContent.contains(pattern)) {
throw TaskResult.failure(
'Expected to find `$pattern` in `$filePath` '
'instead it found:\n$fileContent'
);
}
}
}
TaskResult failure(String message, ProcessResult result) {
print('Unexpected process result:');
print('Exit code: ${result.exitCode}');
......
......@@ -14,7 +14,7 @@ import org.gradle.api.artifacts.maven.MavenDeployer
import org.gradle.api.plugins.MavenPlugin
import org.gradle.api.tasks.Upload
void configureProject(Project project, File outputDir) {
void configureProject(Project project, String outputDir) {
if (!project.hasProperty("android")) {
throw new GradleException("Android property not found.")
}
......@@ -85,10 +85,24 @@ void addAarTask(Project project, variant) {
if (!project.gradle.startParameter.taskNames.contains(taskName)) {
return
}
// NOTE(blasten): `android.defaultPublishConfig` must equal the variant name to build.
// Where variant name is `<product-flavor><Build-Type>`. However, it's too late to configure
// `defaultPublishConfig` at this point. Therefore, the code below ensures that the
// default build config uses the artifacts produced for the specific build variant.
project.uploadArchives.repositories.mavenDeployer {
pom {
artifactId = "${project.name}_${variant.name.toLowerCase()}"
}
}
overrideDefaultPublishConfig(project, variant)
// Generate the Maven artifacts.
finalizedBy "uploadArchives"
}
}
// This method mimics the logic in AGP when `android.defaultPublishConfig` is set in `build.gradle`:
// https://android.googlesource.com/platform/tools/base/+/studio-master-dev/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/variant/VariantHelper.java
//
// Unfortunately, `android.defaultPublishConfig` cannot be overriden at this point since
// AGP already run this code.
void overrideDefaultPublishConfig(Project project, variant) {
String variantName = variant.name.capitalize()
Task bundle = project.tasks.findByName("bundle${variantName}Aar") // gradle:3.2.0
if (bundle == null) {
bundle = project.tasks.findByName("bundle${variantName}") // gradle:3.1.0
......@@ -96,44 +110,39 @@ void addAarTask(Project project, variant) {
if (bundle == null) {
throw new GradleException("Can't generate AAR for variant ${variantName}.");
}
project.uploadArchives.repositories.mavenDeployer {
pom {
artifactId = "${project.name}_${variant.name.toLowerCase()}"
}
}
// Clear the current archives since the current one is assigned based on
// `android.defaultPublishConfig` which defaults to `release`.
// Clear the current archive artifacts since the artifacts are based on `android.defaultPublishConfig`.
project.configurations["archives"].artifacts.clear()
// Add the artifact that will be published.
project.artifacts.add("archives", bundle)
// Generate the Maven artifacts.
finalizedBy "uploadArchives"
def scopeMappings = project.uploadArchives.repositories.mavenDeployer.pom.scopeMappings
// Clear the scope mappings added by AGP since they are based on the current `android.defaultPublishConfig`.
scopeMappings.mappings.clear()
// Add the new mappings.
for (Configuration configuration : flattenConfiguration(variant.runtimeConfiguration)) {
scopeMappings.addMapping(/* priority = */ 300, configuration, "compile")
}
}
Set<Configuration> flattenConfiguration(Configuration configuration) {
Set<Configuration> configs = [configuration]
for (Configuration extend : configuration.extendsFrom) {
configs.addAll(flattenConfiguration(extend))
}
return configs
}
projectsEvaluated {
assert rootProject.hasProperty("is-plugin")
if (rootProject.property("is-plugin").toBoolean()) {
if (rootProject.hasProperty("output-dir")) {
rootProject.buildDir = rootProject.property("output-dir")
} else {
rootProject.buildDir = "../build";
}
assert rootProject.hasProperty("output-dir")
// In plugin projects, the Android library is the root project.
configureProject(rootProject, rootProject.buildDir)
configureProject(rootProject, rootProject.property("output-dir"))
return
}
// In module projects, the Android library project is the `:flutter` subproject.
Project androidLibrarySubproject = rootProject.subprojects.find { it.name == "flutter" }
// In module projects, the `buildDir` is defined in the `:app` subproject.
Project appSubproject = rootProject.subprojects.find { it.name == "app" }
assert appSubproject != null
assert androidLibrarySubproject != null
if (appSubproject.hasProperty("output-dir")) {
appSubproject.buildDir = appSubproject.property("output-dir")
} else {
appSubproject.buildDir = "../build/host"
}
configureProject(androidLibrarySubproject, appSubproject.buildDir)
Project androidLibraryProject = rootProject.subprojects.find { it.name == "flutter" }
assert androidLibraryProject != null
assert androidLibraryProject.hasProperty("output-dir")
configureProject(androidLibraryProject, androidLibraryProject.property("output-dir"))
}
......@@ -220,6 +220,7 @@ class FlutterPlugin implements Plugin<Project> {
}
}
String flutterBuildMode = buildModeFor(buildType)
println "flutter dependency"
// Add the embedding dependency.
addApiDependencies(project, buildType.name,
"io.flutter:flutter_embedding_$flutterBuildMode:1.0.0-$engineVersion")
......@@ -351,7 +352,7 @@ class FlutterPlugin implements Plugin<Project> {
"io.flutter:flutter_embedding_$flutterBuildMode:1.0.0-$engineVersion",
{
// Include the embedding transitive dependencies since plugins may depend on them.
transitive = true
transitive = false
}
)
}
......@@ -619,12 +620,17 @@ class FlutterPlugin implements Plugin<Project> {
addApiDependencies(project, variant.name, project.files {
packFlutterAppAotTask
})
// We build an AAR when this property is defined.
boolean isBuildingAar = project.hasProperty('is-plugin')
// In add to app scenarios, a Gradle project contains a `:flutter` and `:app` project.
// We know that `:flutter` is used as a subproject when these tasks exists and we aren't building an AAR.
Task packageAssets = project.tasks.findByPath(":flutter:package${variant.name.capitalize()}Assets")
Task cleanPackageAssets = project.tasks.findByPath(":flutter:cleanPackage${variant.name.capitalize()}Assets")
// In add to app scenarios, :flutter is a subproject of another Android app.
// We know that :flutter is used as a subproject when these tasks exist.
boolean isUsedAsSubproject = packageAssets && cleanPackageAssets
Task copyFlutterAssetsTask = project.tasks.create(name: "copyFlutterAssets${variant.name.capitalize()}", type: Copy) {
boolean isUsedAsSubproject = packageAssets && cleanPackageAssets && !isBuildingAar
Task copyFlutterAssetsTask = project.tasks.create(
name: "copyFlutterAssets${variant.name.capitalize()}",
type: Copy,
) {
dependsOn compileTasks
compileTasks.each { flutterTask ->
// Add flutter_assets.
......@@ -645,9 +651,10 @@ class FlutterPlugin implements Plugin<Project> {
into mergeAssets.outputDir
}
if (!isUsedAsSubproject) {
def mergeResources = variant.hasProperty("mergeResourcesProvider") ?
variant.mergeResourcesProvider.get() : variant.mergeResources
mergeResources.dependsOn(copyFlutterAssetsTask)
def variantOutput = variant.outputs.first()
def processResources = variantOutput.hasProperty("processResourcesProvider") ?
variantOutput.processResourcesProvider.get() : variantOutput.processResources
processResources.dependsOn(copyFlutterAssetsTask)
return
}
// Flutter module included as a subproject in add to app.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment