Revert "Re-enable AAR plugins when an AndroidX failure occurred (#40810)" (#41042)
This reverts commit 96482eeb5ce5a88e260d53cc513a34800c0817de.
diff --git a/dev/bots/test.dart b/dev/bots/test.dart
index e375213..1d2cdc8 100644
--- a/dev/bots/test.dart
+++ b/dev/bots/test.dart
@@ -1022,7 +1022,6 @@
await _runDevicelabTest('gradle_plugin_fat_apk_test', env: env);
await _runDevicelabTest('gradle_r8_test', env: env);
await _runDevicelabTest('gradle_non_android_plugin_test', env: env);
- await _runDevicelabTest('gradle_jetifier_test', env: env);
}
if (subShard == 'gradle2') {
await _runDevicelabTest('gradle_plugin_bundle_test', env: env);
diff --git a/dev/devicelab/bin/tasks/gradle_jetifier_test.dart b/dev/devicelab/bin/tasks/gradle_jetifier_test.dart
index 86ee0ed..bbabfc2 100644
--- a/dev/devicelab/bin/tasks/gradle_jetifier_test.dart
+++ b/dev/devicelab/bin/tasks/gradle_jetifier_test.dart
@@ -64,7 +64,6 @@
options: <String>[
'apk',
'--target-platform', 'android-arm',
- '--no-shrink',
'--verbose',
],
);
@@ -101,9 +100,7 @@
options: <String>[
'apk',
'--target-platform', 'android-arm',
- '--debug',
- '--no-shrink',
- '--verbose',
+ '--debug', '--verbose',
],
);
});
diff --git a/packages/flutter_tools/gradle/aar_init_script.gradle b/packages/flutter_tools/gradle/aar_init_script.gradle
index 4874aa2..2439da8 100644
--- a/packages/flutter_tools/gradle/aar_init_script.gradle
+++ b/packages/flutter_tools/gradle/aar_init_script.gradle
@@ -7,7 +7,6 @@
// destination of the local repository.
// The local repository will contain the AAR and POM files.
-import java.nio.file.Paths
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.maven.MavenDeployer
@@ -40,32 +39,16 @@
}
}
}
- if (!project.property("is-plugin").toBoolean()) {
- return
- }
- if (project.hasProperty('localEngineOut')) {
- // TODO(egarciad): Support local engine.
- // This most likely requires refactoring `flutter.gradle`, so the logic can be reused.
- throw new GradleException(
- "Local engine isn't supported when building the plugins as AAR. " +
- "See: https://github.com/flutter/flutter/issues/40866")
- }
-
- // This is a Flutter plugin project. Plugin projects don't apply the Flutter Gradle plugin,
- // as a result, add the dependency on the embedding.
- project.repositories {
- maven {
- url "http://download.flutter.io"
- }
- }
- String engineVersion = Paths.get(getFlutterRoot(project), "bin", "internal", "engine.version")
- .toFile().text.trim()
- project.dependencies {
- // Add the embedding dependency.
- compileOnly ("io.flutter:flutter_embedding_release:1.0.0-$engineVersion") {
- // We only need to expose io.flutter.plugin.*
- // No need for the embedding transitive dependencies.
- transitive = false
+ // Check if the project uses the Flutter plugin (defined in flutter.gradle).
+ Boolean usesFlutterPlugin = project.plugins.find { it.class.name == "FlutterPlugin" } != null
+ if (!usesFlutterPlugin) {
+ project.dependencies {
+ // Some plugins don't include `annotations` and they don't set
+ // `android.useAndroidX=true` in `gradle.properties`.
+ compileOnly "androidx.annotation:annotation:+"
+ compileOnly "com.android.support:support-annotations:+"
+ // The Flutter plugin already adds `flutter.jar`.
+ compileOnly project.files("${getFlutterRoot(project)}/bin/cache/artifacts/engine/android-arm-release/flutter.jar")
}
}
}
diff --git a/packages/flutter_tools/gradle/flutter.gradle b/packages/flutter_tools/gradle/flutter.gradle
index 606d3a3..c1067bc 100644
--- a/packages/flutter_tools/gradle/flutter.gradle
+++ b/packages/flutter_tools/gradle/flutter.gradle
@@ -8,8 +8,6 @@
import com.android.build.OutputFile
import java.nio.file.Path
import java.nio.file.Paths
-import java.util.regex.Matcher
-import java.util.regex.Pattern
import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
@@ -258,65 +256,29 @@
*/
private void configurePlugins() {
if (!buildPluginAsAar()) {
- getPluginList().each this.&configurePluginProject
+ getPluginList().each this.&configurePlugin
return
}
- if (useLocalEngine()) {
- throw new GradleException("Local engine isn't supported when building the plugins as AAR")
- }
- List<Project> projects = [project]
- // Module projects set the `hostProjects` extra property in `include_flutter.groovy`.
- // This is required to set the local repository in each host app project.
- if (project.ext.has("hostProjects")) {
- projects.addAll(project.ext.get("hostProjects"))
- }
- // Configure the repository for the plugins.
- projects.each { hostProject ->
- hostProject.repositories {
- maven {
- url "${getPluginBuildDir()}/outputs/repo"
- }
+ addPluginTasks()
+ List<String> tasksToExecute = project.gradle.startParameter.taskNames
+ Set buildTypes = getBuildTypesForTasks(tasksToExecute)
+ if (tasksToExecute.contains("clean")) {
+ // Because the plugins are built during configuration, the task "clean"
+ // cannot run in conjunction with an assembly task.
+ if (!buildTypes.empty) {
+ throw new GradleException("Can't run the clean task along with other assemble tasks")
}
}
- getPluginList().each { pluginName, pluginPath ->
- configurePluginAar(pluginName, pluginPath, project)
+ // Build plugins when a task "assembly*" will be called later.
+ if (!buildTypes.empty) {
+ // Build the plugin during configuration.
+ // This is required when Jetifier is enabled, otherwise the implementation dependency
+ // cannot be added.
+ buildAarPlugins(buildTypes)
}
}
- private static final Pattern GROUP_PATTERN = ~/group\s+\'(.+)\'/
- private static final Pattern PROJECT_NAME_PATTERN = ~/rootProject\.name\s+=\s+\'(.+)\'/
-
- // Adds the plugin AAR dependency to the app project.
- private void configurePluginAar(String pluginName, String pluginPath, Project project) {
- // Extract the group id from the plugin's build.gradle.
- // This is `group '<group-id>'`
- File pluginBuildFile = project.file(Paths.get(pluginPath, "android", "build.gradle"));
- if (!pluginBuildFile.exists()) {
- throw new GradleException("Plugin $pluginName doesn't have the required file $pluginBuildFile.")
- }
-
- Matcher groupParts = GROUP_PATTERN.matcher(pluginBuildFile.text)
- assert groupParts.count == 1
- assert groupParts.hasGroup()
- String groupId = groupParts[0][1]
-
- // Extract the artifact name from the plugin's settings.gradle.
- // This is `rootProject.name = '<artifact-name>'`
- File pluginSettings = project.file(Paths.get(pluginPath, "android", "settings.gradle"));
- if (!pluginSettings.exists()) {
- throw new GradleException("Plugin $pluginName doesn't have the required file $pluginSettings.")
- }
- Matcher projectNameParts = PROJECT_NAME_PATTERN.matcher(pluginSettings.text)
- assert projectNameParts.count == 1
- assert projectNameParts.hasGroup()
- String artifactId = "${projectNameParts[0][1]}_release"
-
- assert !groupId.empty
- project.dependencies.add("api", "$groupId:$artifactId:+")
- }
-
- // Adds the plugin project dependency to the app project .
- private void configurePluginProject(String name, String _) {
+ private void configurePlugin(String name, String _) {
Project pluginProject = project.rootProject.findProject(":$name")
if (pluginProject == null) {
project.logger.error("Plugin project :$name not found. Please update settings.gradle.")
@@ -381,6 +343,93 @@
return androidPlugins
}
+ private void addPluginTasks() {
+ Properties plugins = getPluginList()
+ project.android.buildTypes.each { buildType ->
+ plugins.each { name, path ->
+ String buildModeValue = buildType.debuggable ? "debug" : "release"
+ List<String> taskNameParts = ["build", "plugin", buildModeValue]
+ taskNameParts.addAll(name.split("_"))
+ String taskName = toCammelCase(taskNameParts)
+ // Build types can be extended. For example, a build type can extend the `debug` mode.
+ // In such cases, prevent creating the same task.
+ if (project.tasks.findByName(taskName) == null) {
+ project.tasks.create(name: taskName, type: FlutterPluginTask) {
+ flutterExecutable this.flutterExecutable
+ buildMode buildModeValue
+ verbose isVerbose()
+ pluginDir project.file(path)
+ sourceDir project.file(project.flutter.source)
+ intermediateDir getPluginBuildDir()
+ }
+ }
+ }
+ }
+ }
+
+ private void buildAarPlugins(Set buildTypes) {
+ List<Project> projects = [project]
+ // Module projects set the `hostProjects` extra property in `include_flutter.groovy`.
+ // This is required to set the local repository in each host app project.
+ if (project.ext.has("hostProjects")) {
+ projects.addAll(project.ext.get("hostProjects"))
+ }
+ projects.each { hostProject ->
+ hostProject.repositories {
+ maven {
+ url "${getPluginBuildDir()}/outputs/repo"
+ }
+ }
+ }
+ buildTypes.each { buildType ->
+ project.tasks.withType(FlutterPluginTask).all { pluginTask ->
+ String buildMode = buildType.debuggable ? "debug" : "release"
+ if (pluginTask.buildMode != buildMode) {
+ return
+ }
+ pluginTask.execute()
+ pluginTask.intermediateDir.eachFileRecurse(FILES) { file ->
+ if (file.name != "maven-metadata.xml") {
+ return
+ }
+ def mavenMetadata = new XmlParser().parse(file)
+ String groupId = mavenMetadata.groupId.text()
+ String artifactId = mavenMetadata.artifactId.text()
+
+ if (!artifactId.endsWith(buildMode)) {
+ return
+ }
+ // Add the plugin dependency based on the Maven metadata.
+ addApiDependencies(project, buildType.name, "$groupId:$artifactId:+@aar", {
+ transitive = true
+ })
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a set with the build type names that apply to the given list of tasks
+ * required to configure the plugin dependencies.
+ */
+ private Set getBuildTypesForTasks(List<String> tasksToExecute) {
+ Set buildTypes = []
+ tasksToExecute.each { task ->
+ project.android.buildTypes.each { buildType ->
+ if (task == "androidDependencies" || task.endsWith("dependencies")) {
+ // The tasks to query the dependencies includes all the build types.
+ buildTypes.add(buildType)
+ } else if (task.endsWith("assemble")) {
+ // The `assemble` task includes all the build types.
+ buildTypes.add(buildType)
+ } else if (task.endsWith(buildType.name.capitalize())) {
+ buildTypes.add(buildType)
+ }
+ }
+ }
+ return buildTypes
+ }
+
private static String toCammelCase(List<String> parts) {
if (parts.empty) {
return ""
@@ -878,3 +927,56 @@
buildBundle()
}
}
+
+class FlutterPluginTask extends DefaultTask {
+ File flutterExecutable
+ @Optional @Input
+ Boolean verbose
+ @Input
+ String buildMode
+ @Input
+ File pluginDir
+ @Input
+ File intermediateDir
+ File sourceDir
+
+ @InputFiles
+ FileCollection getSourceFiles() {
+ return project.fileTree(
+ dir: sourceDir,
+ exclude: ["android", "ios"],
+ include: ["pubspec.yaml"]
+ )
+ }
+
+ @OutputDirectory
+ File getOutputDirectory() {
+ return intermediateDir
+ }
+
+ @TaskAction
+ void build() {
+ intermediateDir.mkdirs()
+ project.exec {
+ executable flutterExecutable.absolutePath
+ workingDir pluginDir
+ args "build", "aar"
+ args "--quiet"
+ args "--suppress-analytics"
+ args "--output-dir", "${intermediateDir}"
+ switch (buildMode) {
+ case 'release':
+ args "--release"
+ break
+ case 'debug':
+ args "--debug"
+ break
+ default:
+ assert false
+ }
+ if (verbose) {
+ args "--verbose"
+ }
+ }
+ }
+}
diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart
index dfeca8a..f383329 100644
--- a/packages/flutter_tools/lib/src/android/gradle.dart
+++ b/packages/flutter_tools/lib/src/android/gradle.dart
@@ -22,6 +22,7 @@
import '../base/version.dart';
import '../build_info.dart';
import '../cache.dart';
+import '../features.dart';
import '../flutter_manifest.dart';
import '../globals.dart';
import '../project.dart';
@@ -46,20 +47,18 @@
return _cachedExecutable;
}
- final Map<FlutterProject, GradleProject> _cachedAppProject =
- <FlutterProject, GradleProject>{};
- /// Gets the [GradleProject] for the [project] if built as an app.
- Future<GradleProject> getAppProject(FlutterProject project) async {
- _cachedAppProject[project] ??= await _readGradleProject(project, isLibrary: false);
- return _cachedAppProject[project];
+ GradleProject _cachedAppProject;
+ /// Gets the [GradleProject] for the current [FlutterProject] if built as an app.
+ Future<GradleProject> get appProject async {
+ _cachedAppProject ??= await _readGradleProject(isLibrary: false);
+ return _cachedAppProject;
}
- final Map<FlutterProject, GradleProject> _cachedLibraryProject =
- <FlutterProject, GradleProject>{};
- /// Gets the [GradleProject] for the [project] if built as a library.
- Future<GradleProject> getLibraryProject(FlutterProject project) async {
- _cachedLibraryProject[project] ??= await _readGradleProject(project, isLibrary: true);
- return _cachedLibraryProject[project];
+ GradleProject _cachedLibraryProject;
+ /// Gets the [GradleProject] for the current [FlutterProject] if built as a library.
+ Future<GradleProject> get libraryProject async {
+ _cachedLibraryProject ??= await _readGradleProject(isLibrary: true);
+ return _cachedLibraryProject;
}
}
@@ -134,8 +133,7 @@
case FlutterPluginVersion.managed:
// Fall through. The managed plugin matches plugin v2 for now.
case FlutterPluginVersion.v2:
- final GradleProject gradleProject =
- await gradleUtils.getAppProject(FlutterProject.current());
+ final GradleProject gradleProject = await gradleUtils.appProject;
return fs.file(gradleProject.apkDirectory.childFile('app.apk'));
}
return null;
@@ -211,10 +209,8 @@
// Note: Dependencies are resolved and possibly downloaded as a side-effect
// of calculating the app properties using Gradle. This may take minutes.
-Future<GradleProject> _readGradleProject(
- FlutterProject flutterProject, {
- bool isLibrary = false,
-}) async {
+Future<GradleProject> _readGradleProject({bool isLibrary = false}) async {
+ final FlutterProject flutterProject = FlutterProject.current();
final String gradlew = await gradleUtils.getExecutable(flutterProject);
updateLocalProperties(project: flutterProject);
@@ -222,6 +218,10 @@
final FlutterManifest manifest = flutterProject.manifest;
final Directory hostAppGradleRoot = flutterProject.android.hostAppGradleRoot;
+ if (featureFlags.isPluginAsAarEnabled &&
+ !manifest.isPlugin && !manifest.isModule) {
+ createSettingsAarGradle(hostAppGradleRoot);
+ }
if (manifest.isPlugin) {
assert(isLibrary);
return GradleProject(
@@ -581,9 +581,9 @@
GradleProject gradleProject;
if (manifest.isModule) {
- gradleProject = await gradleUtils.getAppProject(project);
+ gradleProject = await gradleUtils.appProject;
} else if (manifest.isPlugin) {
- gradleProject = await gradleUtils.getLibraryProject(project);
+ gradleProject = await gradleUtils.libraryProject;
} else {
throwToolExit('AARs can only be built for plugin or module projects.');
}
@@ -612,11 +612,13 @@
'-Pflutter-root=$flutterRoot',
'-Poutput-dir=${gradleProject.buildDirectory}',
'-Pis-plugin=${manifest.isPlugin}',
+ '-Dbuild-plugins-as-aars=true',
];
if (target != null && target.isNotEmpty) {
command.add('-Ptarget=$target');
}
+
if (androidBuildInfo.targetArchs.isNotEmpty) {
final String targetPlatforms = androidBuildInfo.targetArchs
.map(getPlatformNameForAndroidArch).join(',');
@@ -631,30 +633,34 @@
command.add(aarTask);
final Stopwatch sw = Stopwatch()..start();
- RunResult result;
+ int exitCode = 1;
+
try {
- result = await processUtils.run(
+ exitCode = await processUtils.stream(
command,
workingDirectory: project.android.hostAppGradleRoot.path,
allowReentrantFlutter: true,
environment: gradleEnv,
+ mapFunction: (String line) {
+ // Always print the full line in verbose mode.
+ if (logger.isVerbose) {
+ return line;
+ }
+ return null;
+ },
);
} finally {
status.stop();
}
- flutterUsage.sendTiming('build', 'gradle-aar', sw.elapsed);
+ flutterUsage.sendTiming('build', 'gradle-aar', Duration(milliseconds: sw.elapsedMilliseconds));
- if (result.exitCode != 0) {
- printStatus(result.stdout, wrap: false);
- printError(result.stderr, wrap: false);
- throwToolExit('Gradle task $aarTask failed with exit code $exitCode.', exitCode: exitCode);
+ if (exitCode != 0) {
+ throwToolExit('Gradle task $aarTask failed with exit code $exitCode', exitCode: exitCode);
}
final Directory repoDirectory = gradleProject.repoDirectory;
if (!repoDirectory.existsSync()) {
- printStatus(result.stdout, wrap: false);
- printError(result.stderr, wrap: false);
- throwToolExit('Gradle task $aarTask failed to produce $repoDirectory.', exitCode: exitCode);
+ throwToolExit('Gradle task $aarTask failed to produce $repoDirectory', exitCode: exitCode);
}
printStatus('Built ${fs.path.relative(repoDirectory.path)}.', color: TerminalColor.green);
}
@@ -724,33 +730,21 @@
FlutterProject flutterProject,
AndroidBuildInfo androidBuildInfo,
String target,
- bool isBuildingBundle, {
- bool shouldBuildPluginAsAar = false,
-}) async {
+ bool isBuildingBundle,
+) async {
final String gradlew = await gradleUtils.getExecutable(flutterProject);
- final GradleProject gradleProject = await gradleUtils.getAppProject(flutterProject);
-
- if (shouldBuildPluginAsAar) {
- // Create a settings.gradle that doesn't import the plugins as subprojects.
- createSettingsAarGradle(flutterProject.android.hostAppGradleRoot);
- await buildPluginsAsAar(
- flutterProject,
- androidBuildInfo,
- buildDirectory: gradleProject.buildDirectory,
- );
- }
-
+ final GradleProject project = await gradleUtils.appProject;
final BuildInfo buildInfo = androidBuildInfo.buildInfo;
String assembleTask;
if (isBuildingBundle) {
- assembleTask = gradleProject.bundleTaskFor(buildInfo);
+ assembleTask = project.bundleTaskFor(buildInfo);
} else {
- assembleTask = gradleProject.assembleTaskFor(buildInfo);
+ assembleTask = project.assembleTaskFor(buildInfo);
}
if (assembleTask == null) {
- printUndefinedTask(gradleProject, buildInfo);
+ printUndefinedTask(project, buildInfo);
throwToolExit('Gradle build aborted.');
}
final Status status = logger.startProgress(
@@ -797,12 +791,13 @@
.map(getPlatformNameForAndroidArch).join(',');
command.add('-Ptarget-platform=$targetPlatforms');
}
- if (shouldBuildPluginAsAar) {
+ if (featureFlags.isPluginAsAarEnabled) {
// Pass a system flag instead of a project flag, so this flag can be
// read from include_flutter.groovy.
command.add('-Dbuild-plugins-as-aars=true');
- // Don't use settings.gradle from the current project since it includes the plugins as subprojects.
- command.add('--settings-file=settings_aar.gradle');
+ if (!flutterProject.manifest.isModule) {
+ command.add('--settings-file=settings_aar.gradle');
+ }
}
command.add(assembleTask);
bool potentialAndroidXFailure = false;
@@ -849,60 +844,24 @@
printStatus('To learn more, see: https://developer.android.com/studio/build/shrink-code', indent: 4);
BuildEvent('r8-failure').send();
} else if (potentialAndroidXFailure) {
- final bool hasPlugins = flutterProject.flutterPluginsFile.existsSync();
- final bool usesAndroidX = isAppUsingAndroidX(flutterProject.android.hostAppGradleRoot);
- if (!hasPlugins) {
- // If the app doesn't use any plugin, then it's unclear where the incompatibility is coming from.
- BuildEvent('android-x-failure', eventError: 'app-not-using-plugins').send();
- }
- if (hasPlugins && !usesAndroidX) {
- // If the app isn't using AndroidX, then the app is likely using a plugin already migrated to AndroidX.
- printStatus('AndroidX incompatibilities may have caused this build to fail. ');
- printStatus('Please migrate your app to AndroidX. See https://goo.gl/CP92wY.');
- BuildEvent('android-x-failure', eventError: 'app-not-using-androidx').send();
- }
- if (hasPlugins && usesAndroidX && shouldBuildPluginAsAar) {
- // This is a dependency conflict instead of an AndroidX failure since by this point
- // the app is using AndroidX, the plugins are built as AARs, Jetifier translated
- // Support libraries for AndroidX equivalents.
- BuildEvent('android-x-failure', eventError: 'using-jetifier').send();
- }
- if (hasPlugins && usesAndroidX && !shouldBuildPluginAsAar) {
- printStatus(
- 'The built failed likely due to AndroidX incompatibilities in a plugin. '
- 'The tool is about to try using Jetfier to solve the incompatibility.'
- );
- BuildEvent('android-x-failure', eventError: 'not-using-jetifier').send();
- // The app is using Androidx, but Jetifier hasn't run yet.
- // Call the current method again, build the plugins as AAR, so Jetifier can translate
- // the dependencies.
- // NOTE: Don't build the plugins as AARs by default since this drastically increases
- // the build time.
- await _buildGradleProjectV2(
- flutterProject,
- androidBuildInfo,
- target,
- isBuildingBundle,
- shouldBuildPluginAsAar: true,
- );
- return;
- }
+ printStatus('AndroidX incompatibilities may have caused this build to fail. See https://goo.gl/CP92wY.');
+ BuildEvent('android-x-failure').send();
}
throwToolExit('Gradle task $assembleTask failed with exit code $exitCode', exitCode: exitCode);
}
flutterUsage.sendTiming('build', 'gradle-v2', Duration(milliseconds: sw.elapsedMilliseconds));
if (!isBuildingBundle) {
- final Iterable<File> apkFiles = findApkFiles(gradleProject, androidBuildInfo);
+ final Iterable<File> apkFiles = findApkFiles(project, androidBuildInfo);
if (apkFiles.isEmpty) {
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(gradleProject.apkDirectory.childFile('app.apk').path);
+ apkFiles.first.copySync(project.apkDirectory.childFile('app.apk').path);
- printTrace('calculateSha: ${gradleProject.apkDirectory}/app.apk');
- final File apkShaFile = gradleProject.apkDirectory.childFile('app.apk.sha1');
+ printTrace('calculateSha: ${project.apkDirectory}/app.apk');
+ final File apkShaFile = project.apkDirectory.childFile('app.apk.sha1');
apkShaFile.writeAsStringSync(_calculateSha(apkFiles.first));
for (File apkFile in apkFiles) {
@@ -916,7 +875,7 @@
color: TerminalColor.green);
}
} else {
- final File bundleFile = findBundleFile(gradleProject, buildInfo);
+ final File bundleFile = findBundleFile(project, buildInfo);
if (bundleFile == null) {
throwToolExit('Gradle build failed to produce an Android bundle package.');
}
@@ -932,61 +891,6 @@
}
}
-/// Returns [true] if the current app uses AndroidX.
-// TODO(egarciad): https://github.com/flutter/flutter/issues/40800
-// Remove `FlutterManifest.usesAndroidX` and provide a unified `AndroidProject.usesAndroidX`.
-@visibleForTesting
-bool isAppUsingAndroidX(Directory androidDirectory) {
- final File properties = androidDirectory.childFile('gradle.properties');
- if (!properties.existsSync()) {
- return false;
- }
- return properties.readAsStringSync().contains('android.useAndroidX=true');
-}
-
-/// Builds the plugins as AARs.
-@visibleForTesting
-Future<void> buildPluginsAsAar(
- FlutterProject flutterProject,
- AndroidBuildInfo androidBuildInfo, {
- String buildDirectory,
-}) async {
- final File flutterPluginFile = flutterProject.flutterPluginsFile;
- if (!flutterPluginFile.existsSync()) {
- return;
- }
- final List<String> plugins = flutterPluginFile.readAsStringSync().split('\n');
- for (String plugin in plugins) {
- final List<String> pluginParts = plugin.split('=');
- if (pluginParts.length != 2) {
- continue;
- }
- final Directory pluginDirectory = fs.directory(pluginParts.last);
- assert(pluginDirectory.existsSync());
-
- final String pluginName = pluginParts.first;
- logger.printStatus('Building plugin $pluginName...');
- try {
- await buildGradleAar(
- project: FlutterProject.fromDirectory(pluginDirectory),
- androidBuildInfo: const AndroidBuildInfo(
- BuildInfo(
- BuildMode.release, // Plugins are built as release.
- null, // Plugins don't define flavors.
- ),
- ),
- target: '',
- outputDir: buildDirectory,
- );
- } on ToolExit {
- // Log the entire plugin entry in `.flutter-plugins` since it
- // includes the plugin name and the version.
- BuildEvent('plugin-aar-failure', eventError: plugin).send();
- throwToolExit('The plugin $pluginName could not be built due to the issue above. ');
- }
- }
-}
-
@visibleForTesting
Iterable<File> findApkFiles(GradleProject project, AndroidBuildInfo androidBuildInfo) {
final Iterable<String> apkFileNames = project.apkFilesFor(androidBuildInfo);
diff --git a/packages/flutter_tools/lib/src/features.dart b/packages/flutter_tools/lib/src/features.dart
index 1701267..cdb1313 100644
--- a/packages/flutter_tools/lib/src/features.dart
+++ b/packages/flutter_tools/lib/src/features.dart
@@ -36,6 +36,9 @@
/// Whether flutter desktop for Windows is enabled.
bool get isWindowsEnabled => _isEnabled(flutterWindowsDesktopFeature);
+ /// Whether plugins are built as AARs in app projects.
+ bool get isPluginAsAarEnabled => _isEnabled(flutterBuildPluginAsAarFeature);
+
// Calculate whether a particular feature is enabled for the current channel.
static bool _isEnabled(Feature feature) {
final String currentChannel = FlutterVersion.instance.channel;
diff --git a/packages/flutter_tools/lib/src/reporting/events.dart b/packages/flutter_tools/lib/src/reporting/events.dart
index 99def6b..8a73f51 100644
--- a/packages/flutter_tools/lib/src/reporting/events.dart
+++ b/packages/flutter_tools/lib/src/reporting/events.dart
@@ -125,7 +125,6 @@
BuildEvent(String parameter, {
this.command,
this.settings,
- this.eventError,
}) : super(
'build' +
(FlutterCommand.current == null ? '' : '-${FlutterCommand.current.name}'),
@@ -133,7 +132,6 @@
final String command;
final String settings;
- final String eventError;
@override
void send() {
@@ -142,8 +140,6 @@
CustomDimensions.buildEventCommand: command,
if (settings != null)
CustomDimensions.buildEventSettings: settings,
- if (eventError != null)
- CustomDimensions.buildEventError: eventError,
});
flutterUsage.sendEvent(category, parameter, parameters: parameters);
}
diff --git a/packages/flutter_tools/lib/src/reporting/usage.dart b/packages/flutter_tools/lib/src/reporting/usage.dart
index a3d225d..0f33c97 100644
--- a/packages/flutter_tools/lib/src/reporting/usage.dart
+++ b/packages/flutter_tools/lib/src/reporting/usage.dart
@@ -53,7 +53,6 @@
commandBuildApkSplitPerAbi, // cd40
commandBuildAppBundleTargetPlatform, // cd41
commandBuildAppBundleBuildMode, // cd42
- buildEventError, // cd43
}
String cdKey(CustomDimensions cd) => 'cd${cd.index + 1}';
diff --git a/packages/flutter_tools/test/general.shard/android/gradle_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_test.dart
index 4450e6d..1ab626d 100644
--- a/packages/flutter_tools/test/general.shard/android/gradle_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/gradle_test.dart
@@ -25,6 +25,7 @@
import '../../src/common.dart';
import '../../src/context.dart';
+import '../../src/mocks.dart';
import '../../src/pubspec_schema.dart';
void main() {
@@ -1154,153 +1155,6 @@
});
});
- group('isAppUsingAndroidX', () {
- FileSystem fs;
-
- setUp(() {
- fs = MemoryFileSystem();
- });
-
- testUsingContext('returns true when the project is using AndroidX', () async {
- final Directory androidDirectory = fs.systemTempDirectory.createTempSync('android.');
-
- androidDirectory
- .childFile('gradle.properties')
- .writeAsStringSync('android.useAndroidX=true');
-
- expect(isAppUsingAndroidX(androidDirectory), isTrue);
-
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('returns false when the project is not using AndroidX', () async {
- final Directory androidDirectory = fs.systemTempDirectory.createTempSync('android.');
-
- androidDirectory
- .childFile('gradle.properties')
- .writeAsStringSync('android.useAndroidX=false');
-
- expect(isAppUsingAndroidX(androidDirectory), isFalse);
-
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('returns false when gradle.properties does not exist', () async {
- final Directory androidDirectory = fs.systemTempDirectory.createTempSync('android.');
-
- expect(isAppUsingAndroidX(androidDirectory), isFalse);
-
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
- });
-
- group('buildPluginsAsAar', () {
- FileSystem fs;
- MockProcessManager mockProcessManager;
- MockAndroidSdk mockAndroidSdk;
-
- setUp(() {
- fs = MemoryFileSystem();
-
- mockProcessManager = MockProcessManager();
- when(mockProcessManager.run(
- any,
- workingDirectory: anyNamed('workingDirectory'),
- environment: anyNamed('environment'),
- )).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
-
- mockAndroidSdk = MockAndroidSdk();
- when(mockAndroidSdk.directory).thenReturn('irrelevant');
- });
-
- testUsingContext('calls gradle', () async {
- final Directory androidDirectory = fs.directory('android.');
- androidDirectory.createSync();
- androidDirectory
- .childFile('pubspec.yaml')
- .writeAsStringSync('name: irrelevant');
-
- final Directory plugin1 = fs.directory('plugin1.');
- plugin1
- ..createSync()
- ..childFile('pubspec.yaml')
- .writeAsStringSync('''
-name: irrelevant
-flutter:
- plugin:
- androidPackage: irrelevant
-''');
- final Directory plugin2 = fs.directory('plugin2.');
- plugin2
- ..createSync()
- ..childFile('pubspec.yaml')
- .writeAsStringSync('''
-name: irrelevant
-flutter:
- plugin:
- androidPackage: irrelevant
-''');
-
- androidDirectory
- .childFile('.flutter-plugins')
- .writeAsStringSync('''
-plugin1=${plugin1.path}
-plugin2=${plugin2.path}
-''');
- final Directory buildDirectory = androidDirectory.childDirectory('build');
- buildDirectory
- .childDirectory('outputs')
- .childDirectory('repo')
- .createSync(recursive: true);
-
- await buildPluginsAsAar(
- FlutterProject.fromPath(androidDirectory.path),
- const AndroidBuildInfo(BuildInfo.release),
- buildDirectory: buildDirectory.path,
- );
-
- final String flutterRoot = fs.path.absolute(Cache.flutterRoot);
- final String initScript = fs.path.join(flutterRoot, 'packages',
- 'flutter_tools', 'gradle', 'aar_init_script.gradle');
- verify(mockProcessManager.run(
- <String>[
- 'gradlew',
- '-I=$initScript',
- '-Pflutter-root=$flutterRoot',
- '-Poutput-dir=${buildDirectory.path}',
- '-Pis-plugin=true',
- '-Ptarget-platform=android-arm,android-arm64',
- 'assembleAarRelease',
- ],
- environment: anyNamed('environment'),
- workingDirectory: plugin1.childDirectory('android').path),
- ).called(1);
-
- verify(mockProcessManager.run(
- <String>[
- 'gradlew',
- '-I=$initScript',
- '-Pflutter-root=$flutterRoot',
- '-Poutput-dir=${buildDirectory.path}',
- '-Pis-plugin=true',
- '-Ptarget-platform=android-arm,android-arm64',
- 'assembleAarRelease',
- ],
- environment: anyNamed('environment'),
- workingDirectory: plugin2.childDirectory('android').path),
- ).called(1);
-
- }, overrides: <Type, Generator>{
- AndroidSdk: () => mockAndroidSdk,
- FileSystem: () => fs,
- GradleUtils: () => FakeGradleUtils(),
- ProcessManager: () => mockProcessManager,
- });
- });
-
group('gradle build', () {
MockAndroidSdk mockAndroidSdk;
MockAndroidStudio mockAndroidStudio;
@@ -1381,13 +1235,11 @@
fs.currentDirectory = 'path/to/project';
// Let any process start. Assert after.
- when(mockProcessManager.run(
+ when(mockProcessManager.start(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'))
- ).thenAnswer(
- (_) async => ProcessResult(1, 0, '', ''),
- );
+ ).thenAnswer((Invocation invocation) => Future<Process>.value(MockProcess()));
fs.directory('build/outputs/repo').createSync(recursive: true);
await buildGradleAar(
@@ -1397,11 +1249,11 @@
target: ''
);
- final List<String> actualGradlewCall = verify(mockProcessManager.run(
+ final List<String> actualGradlewCall = verify(mockProcessManager.start(
captureAny,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')),
- ).captured.last;
+ ).captured.single;
expect(actualGradlewCall, contains('/path/to/project/.android/gradlew'));
expect(actualGradlewCall, contains('-PlocalEngineOut=out/android_arm'));
@@ -1432,14 +1284,6 @@
return FakePlatform.fromPlatform(const LocalPlatform())..operatingSystem = name;
}
-class FakeGradleUtils extends GradleUtils {
- @override
- Future<String> getExecutable(FlutterProject project) async {
- return 'gradlew';
- }
-}
-
-class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockAndroidStudio extends Mock implements AndroidStudio {}
class MockDirectory extends Mock implements Directory {}
class MockFile extends Mock implements File {}
diff --git a/packages/flutter_tools/test/general.shard/features_test.dart b/packages/flutter_tools/test/general.shard/features_test.dart
index a7c978e..3594a6e 100644
--- a/packages/flutter_tools/test/general.shard/features_test.dart
+++ b/packages/flutter_tools/test/general.shard/features_test.dart
@@ -432,6 +432,21 @@
expect(featureFlags.isWindowsEnabled, false);
}));
+
+ /// Plugins as AARS
+ test('plugins built as AARs with config on master', () => testbed.run(() {
+ when(mockFlutterVerion.channel).thenReturn('master');
+ when<bool>(mockFlutterConfig.getValue('enable-build-plugin-as-aar')).thenReturn(false);
+
+ expect(featureFlags.isPluginAsAarEnabled, false);
+ }));
+
+ test('plugins built as AARs with config on dev', () => testbed.run(() {
+ when(mockFlutterVerion.channel).thenReturn('dev');
+ when<bool>(mockFlutterConfig.getValue('enable-build-plugin-as-aar')).thenReturn(false);
+
+ expect(featureFlags.isPluginAsAarEnabled, false);
+ }));
});
}
diff --git a/packages/flutter_tools/test/src/testbed.dart b/packages/flutter_tools/test/src/testbed.dart
index c73a808..446d111 100644
--- a/packages/flutter_tools/test/src/testbed.dart
+++ b/packages/flutter_tools/test/src/testbed.dart
@@ -693,6 +693,7 @@
this.isMacOSEnabled = false,
this.isWebEnabled = false,
this.isWindowsEnabled = false,
+ this.isPluginAsAarEnabled = false,
});
@override
@@ -706,4 +707,7 @@
@override
final bool isWindowsEnabled;
+
+ @override
+ final bool isPluginAsAarEnabled;
}