This reverts commit 96482eeb5ce5a88e260d53cc513a34800c0817de.
This commit is contained in:
parent
919cc97f6a
commit
2c8813c86c
@ -1022,7 +1022,6 @@ Future<void> _androidGradleTests(String subShard) async {
|
|||||||
await _runDevicelabTest('gradle_plugin_fat_apk_test', env: env);
|
await _runDevicelabTest('gradle_plugin_fat_apk_test', env: env);
|
||||||
await _runDevicelabTest('gradle_r8_test', env: env);
|
await _runDevicelabTest('gradle_r8_test', env: env);
|
||||||
await _runDevicelabTest('gradle_non_android_plugin_test', env: env);
|
await _runDevicelabTest('gradle_non_android_plugin_test', env: env);
|
||||||
await _runDevicelabTest('gradle_jetifier_test', env: env);
|
|
||||||
}
|
}
|
||||||
if (subShard == 'gradle2') {
|
if (subShard == 'gradle2') {
|
||||||
await _runDevicelabTest('gradle_plugin_bundle_test', env: env);
|
await _runDevicelabTest('gradle_plugin_bundle_test', env: env);
|
||||||
|
@ -64,7 +64,6 @@ Future<void> main() async {
|
|||||||
options: <String>[
|
options: <String>[
|
||||||
'apk',
|
'apk',
|
||||||
'--target-platform', 'android-arm',
|
'--target-platform', 'android-arm',
|
||||||
'--no-shrink',
|
|
||||||
'--verbose',
|
'--verbose',
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -101,9 +100,7 @@ Future<void> main() async {
|
|||||||
options: <String>[
|
options: <String>[
|
||||||
'apk',
|
'apk',
|
||||||
'--target-platform', 'android-arm',
|
'--target-platform', 'android-arm',
|
||||||
'--debug',
|
'--debug', '--verbose',
|
||||||
'--no-shrink',
|
|
||||||
'--verbose',
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
// destination of the local repository.
|
// destination of the local repository.
|
||||||
// The local repository will contain the AAR and POM files.
|
// The local repository will contain the AAR and POM files.
|
||||||
|
|
||||||
import java.nio.file.Paths
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.artifacts.Configuration
|
import org.gradle.api.artifacts.Configuration
|
||||||
import org.gradle.api.artifacts.maven.MavenDeployer
|
import org.gradle.api.artifacts.maven.MavenDeployer
|
||||||
@ -40,32 +39,16 @@ void configureProject(Project project, File outputDir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!project.property("is-plugin").toBoolean()) {
|
// Check if the project uses the Flutter plugin (defined in flutter.gradle).
|
||||||
return
|
Boolean usesFlutterPlugin = project.plugins.find { it.class.name == "FlutterPlugin" } != null
|
||||||
}
|
if (!usesFlutterPlugin) {
|
||||||
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 {
|
project.dependencies {
|
||||||
// Add the embedding dependency.
|
// Some plugins don't include `annotations` and they don't set
|
||||||
compileOnly ("io.flutter:flutter_embedding_release:1.0.0-$engineVersion") {
|
// `android.useAndroidX=true` in `gradle.properties`.
|
||||||
// We only need to expose io.flutter.plugin.*
|
compileOnly "androidx.annotation:annotation:+"
|
||||||
// No need for the embedding transitive dependencies.
|
compileOnly "com.android.support:support-annotations:+"
|
||||||
transitive = false
|
// The Flutter plugin already adds `flutter.jar`.
|
||||||
|
compileOnly project.files("${getFlutterRoot(project)}/bin/cache/artifacts/engine/android-arm-release/flutter.jar")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,6 @@ import com.android.builder.model.AndroidProject
|
|||||||
import com.android.build.OutputFile
|
import com.android.build.OutputFile
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
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.apache.tools.ant.taskdefs.condition.Os
|
||||||
import org.gradle.api.DefaultTask
|
import org.gradle.api.DefaultTask
|
||||||
import org.gradle.api.GradleException
|
import org.gradle.api.GradleException
|
||||||
@ -258,65 +256,29 @@ class FlutterPlugin implements Plugin<Project> {
|
|||||||
*/
|
*/
|
||||||
private void configurePlugins() {
|
private void configurePlugins() {
|
||||||
if (!buildPluginAsAar()) {
|
if (!buildPluginAsAar()) {
|
||||||
getPluginList().each this.&configurePluginProject
|
getPluginList().each this.&configurePlugin
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (useLocalEngine()) {
|
addPluginTasks()
|
||||||
throw new GradleException("Local engine isn't supported when building the plugins as AAR")
|
List<String> tasksToExecute = project.gradle.startParameter.taskNames
|
||||||
}
|
Set buildTypes = getBuildTypesForTasks(tasksToExecute)
|
||||||
List<Project> projects = [project]
|
if (tasksToExecute.contains("clean")) {
|
||||||
// Module projects set the `hostProjects` extra property in `include_flutter.groovy`.
|
// Because the plugins are built during configuration, the task "clean"
|
||||||
// This is required to set the local repository in each host app project.
|
// cannot run in conjunction with an assembly task.
|
||||||
if (project.ext.has("hostProjects")) {
|
if (!buildTypes.empty) {
|
||||||
projects.addAll(project.ext.get("hostProjects"))
|
throw new GradleException("Can't run the clean task along with other assemble tasks")
|
||||||
}
|
|
||||||
// Configure the repository for the plugins.
|
|
||||||
projects.each { hostProject ->
|
|
||||||
hostProject.repositories {
|
|
||||||
maven {
|
|
||||||
url "${getPluginBuildDir()}/outputs/repo"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// Build plugins when a task "assembly*" will be called later.
|
||||||
getPluginList().each { pluginName, pluginPath ->
|
if (!buildTypes.empty) {
|
||||||
configurePluginAar(pluginName, pluginPath, project)
|
// 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 void configurePlugin(String name, String _) {
|
||||||
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 _) {
|
|
||||||
Project pluginProject = project.rootProject.findProject(":$name")
|
Project pluginProject = project.rootProject.findProject(":$name")
|
||||||
if (pluginProject == null) {
|
if (pluginProject == null) {
|
||||||
project.logger.error("Plugin project :$name not found. Please update settings.gradle.")
|
project.logger.error("Plugin project :$name not found. Please update settings.gradle.")
|
||||||
@ -381,6 +343,93 @@ class FlutterPlugin implements Plugin<Project> {
|
|||||||
return androidPlugins
|
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) {
|
private static String toCammelCase(List<String> parts) {
|
||||||
if (parts.empty) {
|
if (parts.empty) {
|
||||||
return ""
|
return ""
|
||||||
@ -878,3 +927,56 @@ class FlutterTask extends BaseFlutterTask {
|
|||||||
buildBundle()
|
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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ import '../base/utils.dart';
|
|||||||
import '../base/version.dart';
|
import '../base/version.dart';
|
||||||
import '../build_info.dart';
|
import '../build_info.dart';
|
||||||
import '../cache.dart';
|
import '../cache.dart';
|
||||||
|
import '../features.dart';
|
||||||
import '../flutter_manifest.dart';
|
import '../flutter_manifest.dart';
|
||||||
import '../globals.dart';
|
import '../globals.dart';
|
||||||
import '../project.dart';
|
import '../project.dart';
|
||||||
@ -46,20 +47,18 @@ class GradleUtils {
|
|||||||
return _cachedExecutable;
|
return _cachedExecutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<FlutterProject, GradleProject> _cachedAppProject =
|
GradleProject _cachedAppProject;
|
||||||
<FlutterProject, GradleProject>{};
|
/// Gets the [GradleProject] for the current [FlutterProject] if built as an app.
|
||||||
/// Gets the [GradleProject] for the [project] if built as an app.
|
Future<GradleProject> get appProject async {
|
||||||
Future<GradleProject> getAppProject(FlutterProject project) async {
|
_cachedAppProject ??= await _readGradleProject(isLibrary: false);
|
||||||
_cachedAppProject[project] ??= await _readGradleProject(project, isLibrary: false);
|
return _cachedAppProject;
|
||||||
return _cachedAppProject[project];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<FlutterProject, GradleProject> _cachedLibraryProject =
|
GradleProject _cachedLibraryProject;
|
||||||
<FlutterProject, GradleProject>{};
|
/// Gets the [GradleProject] for the current [FlutterProject] if built as a library.
|
||||||
/// Gets the [GradleProject] for the [project] if built as a library.
|
Future<GradleProject> get libraryProject async {
|
||||||
Future<GradleProject> getLibraryProject(FlutterProject project) async {
|
_cachedLibraryProject ??= await _readGradleProject(isLibrary: true);
|
||||||
_cachedLibraryProject[project] ??= await _readGradleProject(project, isLibrary: true);
|
return _cachedLibraryProject;
|
||||||
return _cachedLibraryProject[project];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,8 +133,7 @@ Future<File> getGradleAppOut(AndroidProject androidProject) async {
|
|||||||
case FlutterPluginVersion.managed:
|
case FlutterPluginVersion.managed:
|
||||||
// Fall through. The managed plugin matches plugin v2 for now.
|
// Fall through. The managed plugin matches plugin v2 for now.
|
||||||
case FlutterPluginVersion.v2:
|
case FlutterPluginVersion.v2:
|
||||||
final GradleProject gradleProject =
|
final GradleProject gradleProject = await gradleUtils.appProject;
|
||||||
await gradleUtils.getAppProject(FlutterProject.current());
|
|
||||||
return fs.file(gradleProject.apkDirectory.childFile('app.apk'));
|
return fs.file(gradleProject.apkDirectory.childFile('app.apk'));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -211,10 +209,8 @@ void createSettingsAarGradle(Directory androidDirectory) {
|
|||||||
|
|
||||||
// Note: Dependencies are resolved and possibly downloaded as a side-effect
|
// Note: Dependencies are resolved and possibly downloaded as a side-effect
|
||||||
// of calculating the app properties using Gradle. This may take minutes.
|
// of calculating the app properties using Gradle. This may take minutes.
|
||||||
Future<GradleProject> _readGradleProject(
|
Future<GradleProject> _readGradleProject({bool isLibrary = false}) async {
|
||||||
FlutterProject flutterProject, {
|
final FlutterProject flutterProject = FlutterProject.current();
|
||||||
bool isLibrary = false,
|
|
||||||
}) async {
|
|
||||||
final String gradlew = await gradleUtils.getExecutable(flutterProject);
|
final String gradlew = await gradleUtils.getExecutable(flutterProject);
|
||||||
|
|
||||||
updateLocalProperties(project: flutterProject);
|
updateLocalProperties(project: flutterProject);
|
||||||
@ -222,6 +218,10 @@ Future<GradleProject> _readGradleProject(
|
|||||||
final FlutterManifest manifest = flutterProject.manifest;
|
final FlutterManifest manifest = flutterProject.manifest;
|
||||||
final Directory hostAppGradleRoot = flutterProject.android.hostAppGradleRoot;
|
final Directory hostAppGradleRoot = flutterProject.android.hostAppGradleRoot;
|
||||||
|
|
||||||
|
if (featureFlags.isPluginAsAarEnabled &&
|
||||||
|
!manifest.isPlugin && !manifest.isModule) {
|
||||||
|
createSettingsAarGradle(hostAppGradleRoot);
|
||||||
|
}
|
||||||
if (manifest.isPlugin) {
|
if (manifest.isPlugin) {
|
||||||
assert(isLibrary);
|
assert(isLibrary);
|
||||||
return GradleProject(
|
return GradleProject(
|
||||||
@ -581,9 +581,9 @@ Future<void> buildGradleAar({
|
|||||||
|
|
||||||
GradleProject gradleProject;
|
GradleProject gradleProject;
|
||||||
if (manifest.isModule) {
|
if (manifest.isModule) {
|
||||||
gradleProject = await gradleUtils.getAppProject(project);
|
gradleProject = await gradleUtils.appProject;
|
||||||
} else if (manifest.isPlugin) {
|
} else if (manifest.isPlugin) {
|
||||||
gradleProject = await gradleUtils.getLibraryProject(project);
|
gradleProject = await gradleUtils.libraryProject;
|
||||||
} else {
|
} else {
|
||||||
throwToolExit('AARs can only be built for plugin or module projects.');
|
throwToolExit('AARs can only be built for plugin or module projects.');
|
||||||
}
|
}
|
||||||
@ -612,11 +612,13 @@ Future<void> buildGradleAar({
|
|||||||
'-Pflutter-root=$flutterRoot',
|
'-Pflutter-root=$flutterRoot',
|
||||||
'-Poutput-dir=${gradleProject.buildDirectory}',
|
'-Poutput-dir=${gradleProject.buildDirectory}',
|
||||||
'-Pis-plugin=${manifest.isPlugin}',
|
'-Pis-plugin=${manifest.isPlugin}',
|
||||||
|
'-Dbuild-plugins-as-aars=true',
|
||||||
];
|
];
|
||||||
|
|
||||||
if (target != null && target.isNotEmpty) {
|
if (target != null && target.isNotEmpty) {
|
||||||
command.add('-Ptarget=$target');
|
command.add('-Ptarget=$target');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (androidBuildInfo.targetArchs.isNotEmpty) {
|
if (androidBuildInfo.targetArchs.isNotEmpty) {
|
||||||
final String targetPlatforms = androidBuildInfo.targetArchs
|
final String targetPlatforms = androidBuildInfo.targetArchs
|
||||||
.map(getPlatformNameForAndroidArch).join(',');
|
.map(getPlatformNameForAndroidArch).join(',');
|
||||||
@ -631,30 +633,34 @@ Future<void> buildGradleAar({
|
|||||||
command.add(aarTask);
|
command.add(aarTask);
|
||||||
|
|
||||||
final Stopwatch sw = Stopwatch()..start();
|
final Stopwatch sw = Stopwatch()..start();
|
||||||
RunResult result;
|
int exitCode = 1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = await processUtils.run(
|
exitCode = await processUtils.stream(
|
||||||
command,
|
command,
|
||||||
workingDirectory: project.android.hostAppGradleRoot.path,
|
workingDirectory: project.android.hostAppGradleRoot.path,
|
||||||
allowReentrantFlutter: true,
|
allowReentrantFlutter: true,
|
||||||
environment: gradleEnv,
|
environment: gradleEnv,
|
||||||
|
mapFunction: (String line) {
|
||||||
|
// Always print the full line in verbose mode.
|
||||||
|
if (logger.isVerbose) {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
status.stop();
|
status.stop();
|
||||||
}
|
}
|
||||||
flutterUsage.sendTiming('build', 'gradle-aar', sw.elapsed);
|
flutterUsage.sendTiming('build', 'gradle-aar', Duration(milliseconds: sw.elapsedMilliseconds));
|
||||||
|
|
||||||
if (result.exitCode != 0) {
|
if (exitCode != 0) {
|
||||||
printStatus(result.stdout, wrap: false);
|
throwToolExit('Gradle task $aarTask failed with exit code $exitCode', exitCode: exitCode);
|
||||||
printError(result.stderr, wrap: false);
|
|
||||||
throwToolExit('Gradle task $aarTask failed with exit code $exitCode.', exitCode: exitCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final Directory repoDirectory = gradleProject.repoDirectory;
|
final Directory repoDirectory = gradleProject.repoDirectory;
|
||||||
if (!repoDirectory.existsSync()) {
|
if (!repoDirectory.existsSync()) {
|
||||||
printStatus(result.stdout, wrap: false);
|
throwToolExit('Gradle task $aarTask failed to produce $repoDirectory', exitCode: exitCode);
|
||||||
printError(result.stderr, wrap: false);
|
|
||||||
throwToolExit('Gradle task $aarTask failed to produce $repoDirectory.', exitCode: exitCode);
|
|
||||||
}
|
}
|
||||||
printStatus('Built ${fs.path.relative(repoDirectory.path)}.', color: TerminalColor.green);
|
printStatus('Built ${fs.path.relative(repoDirectory.path)}.', color: TerminalColor.green);
|
||||||
}
|
}
|
||||||
@ -724,33 +730,21 @@ Future<void> _buildGradleProjectV2(
|
|||||||
FlutterProject flutterProject,
|
FlutterProject flutterProject,
|
||||||
AndroidBuildInfo androidBuildInfo,
|
AndroidBuildInfo androidBuildInfo,
|
||||||
String target,
|
String target,
|
||||||
bool isBuildingBundle, {
|
bool isBuildingBundle,
|
||||||
bool shouldBuildPluginAsAar = false,
|
) async {
|
||||||
}) async {
|
|
||||||
final String gradlew = await gradleUtils.getExecutable(flutterProject);
|
final String gradlew = await gradleUtils.getExecutable(flutterProject);
|
||||||
final GradleProject gradleProject = await gradleUtils.getAppProject(flutterProject);
|
final GradleProject project = await gradleUtils.appProject;
|
||||||
|
|
||||||
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 BuildInfo buildInfo = androidBuildInfo.buildInfo;
|
final BuildInfo buildInfo = androidBuildInfo.buildInfo;
|
||||||
|
|
||||||
String assembleTask;
|
String assembleTask;
|
||||||
|
|
||||||
if (isBuildingBundle) {
|
if (isBuildingBundle) {
|
||||||
assembleTask = gradleProject.bundleTaskFor(buildInfo);
|
assembleTask = project.bundleTaskFor(buildInfo);
|
||||||
} else {
|
} else {
|
||||||
assembleTask = gradleProject.assembleTaskFor(buildInfo);
|
assembleTask = project.assembleTaskFor(buildInfo);
|
||||||
}
|
}
|
||||||
if (assembleTask == null) {
|
if (assembleTask == null) {
|
||||||
printUndefinedTask(gradleProject, buildInfo);
|
printUndefinedTask(project, buildInfo);
|
||||||
throwToolExit('Gradle build aborted.');
|
throwToolExit('Gradle build aborted.');
|
||||||
}
|
}
|
||||||
final Status status = logger.startProgress(
|
final Status status = logger.startProgress(
|
||||||
@ -797,13 +791,14 @@ Future<void> _buildGradleProjectV2(
|
|||||||
.map(getPlatformNameForAndroidArch).join(',');
|
.map(getPlatformNameForAndroidArch).join(',');
|
||||||
command.add('-Ptarget-platform=$targetPlatforms');
|
command.add('-Ptarget-platform=$targetPlatforms');
|
||||||
}
|
}
|
||||||
if (shouldBuildPluginAsAar) {
|
if (featureFlags.isPluginAsAarEnabled) {
|
||||||
// Pass a system flag instead of a project flag, so this flag can be
|
// Pass a system flag instead of a project flag, so this flag can be
|
||||||
// read from include_flutter.groovy.
|
// read from include_flutter.groovy.
|
||||||
command.add('-Dbuild-plugins-as-aars=true');
|
command.add('-Dbuild-plugins-as-aars=true');
|
||||||
// Don't use settings.gradle from the current project since it includes the plugins as subprojects.
|
if (!flutterProject.manifest.isModule) {
|
||||||
command.add('--settings-file=settings_aar.gradle');
|
command.add('--settings-file=settings_aar.gradle');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
command.add(assembleTask);
|
command.add(assembleTask);
|
||||||
bool potentialAndroidXFailure = false;
|
bool potentialAndroidXFailure = false;
|
||||||
bool potentialR8Failure = false;
|
bool potentialR8Failure = false;
|
||||||
@ -849,60 +844,24 @@ Future<void> _buildGradleProjectV2(
|
|||||||
printStatus('To learn more, see: https://developer.android.com/studio/build/shrink-code', indent: 4);
|
printStatus('To learn more, see: https://developer.android.com/studio/build/shrink-code', indent: 4);
|
||||||
BuildEvent('r8-failure').send();
|
BuildEvent('r8-failure').send();
|
||||||
} else if (potentialAndroidXFailure) {
|
} else if (potentialAndroidXFailure) {
|
||||||
final bool hasPlugins = flutterProject.flutterPluginsFile.existsSync();
|
printStatus('AndroidX incompatibilities may have caused this build to fail. See https://goo.gl/CP92wY.');
|
||||||
final bool usesAndroidX = isAppUsingAndroidX(flutterProject.android.hostAppGradleRoot);
|
BuildEvent('android-x-failure').send();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throwToolExit('Gradle task $assembleTask failed with exit code $exitCode', exitCode: exitCode);
|
throwToolExit('Gradle task $assembleTask failed with exit code $exitCode', exitCode: exitCode);
|
||||||
}
|
}
|
||||||
flutterUsage.sendTiming('build', 'gradle-v2', Duration(milliseconds: sw.elapsedMilliseconds));
|
flutterUsage.sendTiming('build', 'gradle-v2', Duration(milliseconds: sw.elapsedMilliseconds));
|
||||||
|
|
||||||
if (!isBuildingBundle) {
|
if (!isBuildingBundle) {
|
||||||
final Iterable<File> apkFiles = findApkFiles(gradleProject, androidBuildInfo);
|
final Iterable<File> apkFiles = findApkFiles(project, androidBuildInfo);
|
||||||
if (apkFiles.isEmpty) {
|
if (apkFiles.isEmpty) {
|
||||||
throwToolExit('Gradle build failed to produce an Android package.');
|
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.
|
// Copy the first APK to app.apk, so `flutter run`, `flutter install`, etc. can find it.
|
||||||
// TODO(blasten): Handle multiple APKs.
|
// 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');
|
printTrace('calculateSha: ${project.apkDirectory}/app.apk');
|
||||||
final File apkShaFile = gradleProject.apkDirectory.childFile('app.apk.sha1');
|
final File apkShaFile = project.apkDirectory.childFile('app.apk.sha1');
|
||||||
apkShaFile.writeAsStringSync(_calculateSha(apkFiles.first));
|
apkShaFile.writeAsStringSync(_calculateSha(apkFiles.first));
|
||||||
|
|
||||||
for (File apkFile in apkFiles) {
|
for (File apkFile in apkFiles) {
|
||||||
@ -916,7 +875,7 @@ Future<void> _buildGradleProjectV2(
|
|||||||
color: TerminalColor.green);
|
color: TerminalColor.green);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final File bundleFile = findBundleFile(gradleProject, buildInfo);
|
final File bundleFile = findBundleFile(project, buildInfo);
|
||||||
if (bundleFile == null) {
|
if (bundleFile == null) {
|
||||||
throwToolExit('Gradle build failed to produce an Android bundle package.');
|
throwToolExit('Gradle build failed to produce an Android bundle package.');
|
||||||
}
|
}
|
||||||
@ -932,61 +891,6 @@ Future<void> _buildGradleProjectV2(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
@visibleForTesting
|
||||||
Iterable<File> findApkFiles(GradleProject project, AndroidBuildInfo androidBuildInfo) {
|
Iterable<File> findApkFiles(GradleProject project, AndroidBuildInfo androidBuildInfo) {
|
||||||
final Iterable<String> apkFileNames = project.apkFilesFor(androidBuildInfo);
|
final Iterable<String> apkFileNames = project.apkFilesFor(androidBuildInfo);
|
||||||
|
@ -36,6 +36,9 @@ class FeatureFlags {
|
|||||||
/// Whether flutter desktop for Windows is enabled.
|
/// Whether flutter desktop for Windows is enabled.
|
||||||
bool get isWindowsEnabled => _isEnabled(flutterWindowsDesktopFeature);
|
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.
|
// Calculate whether a particular feature is enabled for the current channel.
|
||||||
static bool _isEnabled(Feature feature) {
|
static bool _isEnabled(Feature feature) {
|
||||||
final String currentChannel = FlutterVersion.instance.channel;
|
final String currentChannel = FlutterVersion.instance.channel;
|
||||||
|
@ -125,7 +125,6 @@ class BuildEvent extends UsageEvent {
|
|||||||
BuildEvent(String parameter, {
|
BuildEvent(String parameter, {
|
||||||
this.command,
|
this.command,
|
||||||
this.settings,
|
this.settings,
|
||||||
this.eventError,
|
|
||||||
}) : super(
|
}) : super(
|
||||||
'build' +
|
'build' +
|
||||||
(FlutterCommand.current == null ? '' : '-${FlutterCommand.current.name}'),
|
(FlutterCommand.current == null ? '' : '-${FlutterCommand.current.name}'),
|
||||||
@ -133,7 +132,6 @@ class BuildEvent extends UsageEvent {
|
|||||||
|
|
||||||
final String command;
|
final String command;
|
||||||
final String settings;
|
final String settings;
|
||||||
final String eventError;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void send() {
|
void send() {
|
||||||
@ -142,8 +140,6 @@ class BuildEvent extends UsageEvent {
|
|||||||
CustomDimensions.buildEventCommand: command,
|
CustomDimensions.buildEventCommand: command,
|
||||||
if (settings != null)
|
if (settings != null)
|
||||||
CustomDimensions.buildEventSettings: settings,
|
CustomDimensions.buildEventSettings: settings,
|
||||||
if (eventError != null)
|
|
||||||
CustomDimensions.buildEventError: eventError,
|
|
||||||
});
|
});
|
||||||
flutterUsage.sendEvent(category, parameter, parameters: parameters);
|
flutterUsage.sendEvent(category, parameter, parameters: parameters);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,6 @@ enum CustomDimensions {
|
|||||||
commandBuildApkSplitPerAbi, // cd40
|
commandBuildApkSplitPerAbi, // cd40
|
||||||
commandBuildAppBundleTargetPlatform, // cd41
|
commandBuildAppBundleTargetPlatform, // cd41
|
||||||
commandBuildAppBundleBuildMode, // cd42
|
commandBuildAppBundleBuildMode, // cd42
|
||||||
buildEventError, // cd43
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String cdKey(CustomDimensions cd) => 'cd${cd.index + 1}';
|
String cdKey(CustomDimensions cd) => 'cd${cd.index + 1}';
|
||||||
|
@ -25,6 +25,7 @@ import 'package:process/process.dart';
|
|||||||
|
|
||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
import '../../src/context.dart';
|
import '../../src/context.dart';
|
||||||
|
import '../../src/mocks.dart';
|
||||||
import '../../src/pubspec_schema.dart';
|
import '../../src/pubspec_schema.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@ -1154,153 +1155,6 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
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', () {
|
group('gradle build', () {
|
||||||
MockAndroidSdk mockAndroidSdk;
|
MockAndroidSdk mockAndroidSdk;
|
||||||
MockAndroidStudio mockAndroidStudio;
|
MockAndroidStudio mockAndroidStudio;
|
||||||
@ -1381,13 +1235,11 @@ plugin2=${plugin2.path}
|
|||||||
fs.currentDirectory = 'path/to/project';
|
fs.currentDirectory = 'path/to/project';
|
||||||
|
|
||||||
// Let any process start. Assert after.
|
// Let any process start. Assert after.
|
||||||
when(mockProcessManager.run(
|
when(mockProcessManager.start(
|
||||||
any,
|
any,
|
||||||
environment: anyNamed('environment'),
|
environment: anyNamed('environment'),
|
||||||
workingDirectory: anyNamed('workingDirectory'))
|
workingDirectory: anyNamed('workingDirectory'))
|
||||||
).thenAnswer(
|
).thenAnswer((Invocation invocation) => Future<Process>.value(MockProcess()));
|
||||||
(_) async => ProcessResult(1, 0, '', ''),
|
|
||||||
);
|
|
||||||
fs.directory('build/outputs/repo').createSync(recursive: true);
|
fs.directory('build/outputs/repo').createSync(recursive: true);
|
||||||
|
|
||||||
await buildGradleAar(
|
await buildGradleAar(
|
||||||
@ -1397,11 +1249,11 @@ plugin2=${plugin2.path}
|
|||||||
target: ''
|
target: ''
|
||||||
);
|
);
|
||||||
|
|
||||||
final List<String> actualGradlewCall = verify(mockProcessManager.run(
|
final List<String> actualGradlewCall = verify(mockProcessManager.start(
|
||||||
captureAny,
|
captureAny,
|
||||||
environment: anyNamed('environment'),
|
environment: anyNamed('environment'),
|
||||||
workingDirectory: anyNamed('workingDirectory')),
|
workingDirectory: anyNamed('workingDirectory')),
|
||||||
).captured.last;
|
).captured.single;
|
||||||
|
|
||||||
expect(actualGradlewCall, contains('/path/to/project/.android/gradlew'));
|
expect(actualGradlewCall, contains('/path/to/project/.android/gradlew'));
|
||||||
expect(actualGradlewCall, contains('-PlocalEngineOut=out/android_arm'));
|
expect(actualGradlewCall, contains('-PlocalEngineOut=out/android_arm'));
|
||||||
@ -1432,14 +1284,6 @@ Platform fakePlatform(String name) {
|
|||||||
return FakePlatform.fromPlatform(const LocalPlatform())..operatingSystem = name;
|
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 MockAndroidStudio extends Mock implements AndroidStudio {}
|
||||||
class MockDirectory extends Mock implements Directory {}
|
class MockDirectory extends Mock implements Directory {}
|
||||||
class MockFile extends Mock implements File {}
|
class MockFile extends Mock implements File {}
|
||||||
|
@ -432,6 +432,21 @@ void main() {
|
|||||||
|
|
||||||
expect(featureFlags.isWindowsEnabled, false);
|
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);
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,6 +693,7 @@ class TestFeatureFlags implements FeatureFlags {
|
|||||||
this.isMacOSEnabled = false,
|
this.isMacOSEnabled = false,
|
||||||
this.isWebEnabled = false,
|
this.isWebEnabled = false,
|
||||||
this.isWindowsEnabled = false,
|
this.isWindowsEnabled = false,
|
||||||
|
this.isPluginAsAarEnabled = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -706,4 +707,7 @@ class TestFeatureFlags implements FeatureFlags {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
final bool isWindowsEnabled;
|
final bool isWindowsEnabled;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final bool isPluginAsAarEnabled;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user