Skip to content

Commit 56e11ae

Browse files
gmackallGray Mackall
andauthored
[reland] Convert the Flutter Gradle Plugin entirely to Kotlin source (flutter#166676)
Relands flutter#166114. The original PR failed this postsubmit https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8718287794116896097/+/u/run_engine_dependency_proxy_test/stdout Because ``` Task result: { "success": false, "reason": "Task failed: Expected Android engine maven dependency URL to resolve to https://storage.googleapis.com/download.flutter.io. Got https://storage.googleapis.com//download.flutter.io instead" } ``` which was because apparently in Groovy ```groovy String foo = "" if (foo) { // branch } ``` Evaluates to false (i.e. does not take the branch). So we need to check if the `engineRealm` string is empty, which is what the additional commit does. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: Gray Mackall <[email protected]>
1 parent a333757 commit 56e11ae

26 files changed

+1747
-1121
lines changed

packages/flutter_tools/gradle/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ gradlePlugin {
3434
// The "flutterPlugin" name isn't used anywhere.
3535
create("flutterPlugin") {
3636
id = "dev.flutter.flutter-gradle-plugin"
37-
implementationClass = "FlutterPlugin"
37+
implementationClass = "com.flutter.gradle.FlutterPlugin"
3838
}
3939
// The "flutterAppPluginLoaderPlugin" name isn't used anywhere.
4040
create("flutterAppPluginLoaderPlugin") {

packages/flutter_tools/gradle/src/main/groovy/flutter.groovy

Lines changed: 0 additions & 722 deletions
This file was deleted.

packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt

Lines changed: 743 additions & 0 deletions
Large diffs are not rendered by default.

packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginConstants.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ object FlutterPluginConstants {
2525
const val INTERMEDIATES_DIR = "intermediates"
2626
const val FLUTTER_STORAGE_BASE_URL = "FLUTTER_STORAGE_BASE_URL"
2727
const val DEFAULT_MAVEN_HOST = "https://storage.googleapis.com"
28-
const val WEBSITE_DEPLOYMENT_ANDROID_BUILD_CONFIG = "https://flutter.dev/to/review-gradle-config"
2928

3029
/** Maps platforms to ABI architectures. */
3130
@JvmStatic val PLATFORM_ARCH_MAP =
@@ -42,7 +41,7 @@ object FlutterPluginConstants {
4241
* Otherwise, the Play Store will complain that the APK variants have the same version.
4342
*/
4443
@JvmStatic val ABI_VERSION =
45-
mapOf<String, Int>( // Explicit type for clarity, though inferred
44+
mapOf<String, Int>(
4645
ARCH_ARM32 to 1,
4746
ARCH_ARM64 to 2,
4847
ARCH_X86 to 3,

packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt

Lines changed: 6 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.android.build.gradle.api.ApplicationVariant
1010
import com.android.build.gradle.api.BaseVariantOutput
1111
import com.android.build.gradle.tasks.ProcessAndroidResources
1212
import com.android.builder.model.BuildType
13+
import com.flutter.gradle.plugins.PluginHandler
1314
import groovy.lang.Closure
1415
import groovy.util.Node
1516
import groovy.util.XmlParser
@@ -139,19 +140,6 @@ object FlutterPluginUtils {
139140

140141
// TODO(54566): Can remove this function and its call sites once resolved.
141142

142-
/**
143-
* Returns `true` if the given project is a plugin project having an `android` directory
144-
* containing a `build.gradle` or `build.gradle.kts` file.
145-
*/
146-
@JvmStatic
147-
@JvmName("pluginSupportsAndroidPlatform")
148-
internal fun pluginSupportsAndroidPlatform(project: Project): Boolean {
149-
val buildGradle = File(File(project.projectDir.parentFile, "android"), "build.gradle")
150-
val buildGradleKts =
151-
File(File(project.projectDir.parentFile, "android"), "build.gradle.kts")
152-
return buildGradle.exists() || buildGradleKts.exists()
153-
}
154-
155143
/**
156144
* Returns the Gradle settings script for the build. When both Groovy and
157145
* Kotlin variants exist, then Groovy (settings.gradle) is preferred over
@@ -406,7 +394,7 @@ object FlutterPluginUtils {
406394
return project.property(PROP_LOCAL_ENGINE_BUILD_MODE) == flutterBuildMode
407395
}
408396

409-
private fun getAndroidExtension(project: Project): BaseExtension {
397+
internal fun getAndroidExtension(project: Project): BaseExtension {
410398
// Common supertype of the android extension types.
411399
// But maybe this should be https://developer.android.com/reference/tools/gradle-api/8.7/com/android/build/api/dsl/TestedExtension.
412400
return project.extensions.findByType(BaseExtension::class.java)!!
@@ -611,7 +599,7 @@ object FlutterPluginUtils {
611599

612600
// Otherwise, point to an empty CMakeLists.txt, and ignore associated warnings.
613601
gradleProjectAndroidExtension.externalNativeBuild.cmake.path(
614-
"$flutterSdkRootPath/packages/flutter_tools/gradle/src/main/groovy/CMakeLists.txt"
602+
"$flutterSdkRootPath/packages/flutter_tools/gradle/src/main/scripts/CMakeLists.txt"
615603
)
616604

617605
// AGP defaults to outputting build artifacts in `android/app/.cxx`. This directory is a
@@ -656,7 +644,7 @@ object FlutterPluginUtils {
656644
internal fun addFlutterDependencies(
657645
project: Project,
658646
buildType: BuildType,
659-
pluginList: List<Map<String?, Any?>>,
647+
pluginHandler: PluginHandler,
660648
engineVersion: String
661649
) {
662650
val flutterBuildMode: String = buildModeFor(buildType)
@@ -676,11 +664,9 @@ object FlutterPluginUtils {
676664
// embedding.
677665
val pluginsThatIncludeFlutterEmbeddingAsTransitiveDependency: List<Map<String?, Any?>> =
678666
if (flutterBuildMode == "release") {
679-
getPluginListWithoutDevDependencies(
680-
pluginList
681-
)
667+
pluginHandler.getPluginListWithoutDevDependencies()
682668
} else {
683-
pluginList
669+
pluginHandler.getPluginList()
684670
}
685671

686672
if (!isFlutterAppProject(project) || pluginsThatIncludeFlutterEmbeddingAsTransitiveDependency.isEmpty()) {
@@ -702,143 +688,6 @@ object FlutterPluginUtils {
702688
}
703689
}
704690

705-
/**
706-
* Gets the list of plugins (as map) that support the Android platform and are dependencies of the
707-
* Android project excluding dev dependencies.
708-
*
709-
* The map value contains either the plugins `name` (String),
710-
* its `path` (String), or its `dependencies` (List<String>).
711-
* See [NativePluginLoader#getPlugins] in packages/flutter_tools/gradle/src/main/scripts/native_plugin_loader.gradle.kts
712-
*/
713-
private fun getPluginListWithoutDevDependencies(pluginList: List<Map<String?, Any?>>): List<Map<String?, Any?>> =
714-
pluginList.filter { pluginObject -> pluginObject["dev_dependency"] == false }
715-
716-
/**
717-
* Add the dependencies on other plugin projects to the plugin project.
718-
* A plugin A can depend on plugin B. As a result, this dependency must be surfaced by
719-
* making the Gradle plugin project A depend on the Gradle plugin project B.
720-
*/
721-
@JvmStatic
722-
@JvmName("configurePluginDependencies")
723-
internal fun configurePluginDependencies(
724-
project: Project,
725-
pluginObject: Map<String?, Any?>
726-
) {
727-
val pluginName: String =
728-
requireNotNull(pluginObject["name"] as? String) {
729-
"Missing valid \"name\" property for plugin object: $pluginObject"
730-
}
731-
val pluginProject: Project = project.rootProject.findProject(":$pluginName") ?: return
732-
733-
getAndroidExtension(project).buildTypes.forEach { buildType ->
734-
val flutterBuildMode: String = buildModeFor(buildType)
735-
if (flutterBuildMode == "release" && (pluginObject["dev_dependency"] as? Boolean == true)) {
736-
// This plugin is a dev dependency will not be included in the
737-
// release build, so no need to add its dependencies.
738-
return@forEach
739-
}
740-
val dependencies = requireNotNull(pluginObject["dependencies"] as? List<*>)
741-
dependencies.forEach innerForEach@{ pluginDependencyName ->
742-
check(pluginDependencyName is String)
743-
if (pluginDependencyName.isEmpty()) {
744-
return@innerForEach
745-
}
746-
747-
val dependencyProject =
748-
project.rootProject.findProject(":$pluginDependencyName") ?: return@innerForEach
749-
pluginProject.afterEvaluate {
750-
pluginProject.dependencies.add("implementation", dependencyProject)
751-
}
752-
}
753-
}
754-
}
755-
756-
/**
757-
* Performs configuration related to the plugin's Gradle [Project], including
758-
* 1. Adding the plugin itself as a dependency to the main project.
759-
* 2. Adding the main project's build types to the plugin's build types.
760-
* 3. Adding a dependency on the Flutter embedding to the plugin.
761-
*
762-
* Should only be called on plugins that support the Android platform.
763-
*/
764-
@JvmStatic
765-
@JvmName("configurePluginProject")
766-
internal fun configurePluginProject(
767-
project: Project,
768-
pluginObject: Map<String?, Any?>,
769-
engineVersion: String
770-
) {
771-
// TODO(gmackall): should guard this with a pluginObject.contains().
772-
val pluginName =
773-
requireNotNull(pluginObject["name"] as? String) { "Plugin name must be a string for plugin object: $pluginObject" }
774-
val pluginProject: Project = project.rootProject.findProject(":$pluginName") ?: return
775-
776-
// Apply the "flutter" Gradle extension to plugins so that they can use it's vended
777-
// compile/target/min sdk values.
778-
pluginProject.extensions.create("flutter", FlutterExtension::class.java)
779-
780-
// Add plugin dependency to the app project. We only want to add dependency
781-
// for dev dependencies in non-release builds.
782-
project.afterEvaluate {
783-
getAndroidExtension(project).buildTypes.forEach { buildType ->
784-
if (!(pluginObject["dev_dependency"] as Boolean) || buildType.name != "release") {
785-
project.dependencies.add("${buildType.name}Api", pluginProject)
786-
}
787-
}
788-
}
789-
790-
// Wait until the Android plugin loaded.
791-
pluginProject.afterEvaluate {
792-
// Checks if there is a mismatch between the plugin compileSdkVersion and the project compileSdkVersion.
793-
val projectCompileSdkVersion: String = getCompileSdkFromProject(project)
794-
val pluginCompileSdkVersion: String = getCompileSdkFromProject(pluginProject)
795-
// TODO(gmackall): This is doing a string comparison, which is odd and also can be wrong
796-
// when comparing preview versions (against non preview, and also in the
797-
// case of alphabet reset which happened with "Baklava".
798-
if (pluginCompileSdkVersion > projectCompileSdkVersion) {
799-
project.logger.quiet("Warning: The plugin $pluginName requires Android SDK version $pluginCompileSdkVersion or higher.")
800-
project.logger.quiet(
801-
"For more information about build configuration, see ${FlutterPluginConstants.WEBSITE_DEPLOYMENT_ANDROID_BUILD_CONFIG}."
802-
)
803-
}
804-
805-
getAndroidExtension(project).buildTypes.forEach { buildType ->
806-
addEmbeddingDependencyToPlugin(project, pluginProject, buildType, engineVersion)
807-
}
808-
}
809-
}
810-
811-
private fun addEmbeddingDependencyToPlugin(
812-
project: Project,
813-
pluginProject: Project,
814-
buildType: BuildType,
815-
engineVersion: String
816-
) {
817-
val flutterBuildMode: String = buildModeFor(buildType)
818-
// TODO(gmackall): this should be safe to remove, as the minimum required AGP is well above
819-
// 3.5. We should try to remove it.
820-
// In AGP 3.5, the embedding must be added as an API implementation,
821-
// so java8 features are desugared against the runtime classpath.
822-
// For more, see https://github.com/flutter/flutter/issues/40126
823-
if (!supportsBuildMode(pluginProject, flutterBuildMode)) {
824-
return
825-
}
826-
if (!pluginProject.hasProperty("android")) {
827-
return
828-
}
829-
830-
// Copy build types from the app to the plugin.
831-
// This allows to build apps with plugins and custom build types or flavors.
832-
getAndroidExtension(pluginProject).buildTypes.addAll(getAndroidExtension(project).buildTypes)
833-
834-
// The embedding is API dependency of the plugin, so the AGP is able to desugar
835-
// default method implementations when the interface is implemented by a plugin.
836-
//
837-
// See https://issuetracker.google.com/139821726, and
838-
// https://github.com/flutter/flutter/issues/72185 for more details.
839-
addApiDependencies(pluginProject, buildType.name, "io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion")
840-
}
841-
842691
// ------------------ Task adders (a subset of the above category)
843692

844693
// Add a task that can be called on flutter projects that prints the Java version used in Gradle.

packages/flutter_tools/gradle/src/main/kotlin/NativePluginLoaderReflectionBridge.kt

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,41 +17,37 @@ import java.io.File
1717
*/
1818

1919
object NativePluginLoaderReflectionBridge {
20-
private var nativePluginLoader: Any? = null
21-
2220
/**
2321
* An abstraction to hide reflection from calling sites. See ../scripts/native_plugin_loader.gradle.kts.
2422
*/
25-
@JvmStatic
2623
fun getPlugins(
2724
extraProperties: ExtraPropertiesExtension,
2825
flutterProjectRoot: File
29-
): List<Map<String, Any>> {
30-
nativePluginLoader = extraProperties.get("nativePluginLoader")!!
26+
): List<Map<String?, Any?>> {
27+
val nativePluginLoader = extraProperties.get("nativePluginLoader")!!
3128

3229
@Suppress("UNCHECKED_CAST")
33-
val pluginList: List<Map<String, Any>> =
34-
nativePluginLoader!!::class
30+
val pluginList: List<Map<String?, Any?>> =
31+
nativePluginLoader::class
3532
.members
3633
.firstOrNull { it.name == "getPlugins" }
37-
?.call(nativePluginLoader, flutterProjectRoot) as List<Map<String, Any>>
34+
?.call(nativePluginLoader, flutterProjectRoot) as List<Map<String?, Any?>>
3835

3936
return pluginList
4037
}
4138

4239
/**
4340
* An abstraction to hide reflection from calling sites. See ../scripts/native_plugin_loader.gradle.kts.
4441
*/
45-
@JvmStatic
4642
fun getDependenciesMetadata(
4743
extraProperties: ExtraPropertiesExtension,
4844
flutterProjectRoot: File
4945
): Map<String, Any> {
50-
nativePluginLoader = extraProperties.get("nativePluginLoader")!!
46+
val nativePluginLoader = extraProperties.get("nativePluginLoader")!!
5147

5248
@Suppress("UNCHECKED_CAST")
5349
val dependenciesMetadata: Map<String, Any> =
54-
nativePluginLoader!!::class
50+
nativePluginLoader::class
5551
.members
5652
.firstOrNull { it.name == "dependenciesMetadata" }
5753
?.call(nativePluginLoader, flutterProjectRoot) as Map<String, Any>

0 commit comments

Comments
 (0)