Remove handling of the legacy .flutter-plugins file in PluginHandler.kt. (#169317)

As of https://github.com/flutter/flutter/pull/169283 it's impossible for
the `.flutter-plugins` file to exist outside of unit tests.
This commit is contained in:
Matan Lurey 2025-05-23 13:02:02 -04:00 committed by GitHub
parent 171e272cf7
commit 5f99c893b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 0 additions and 192 deletions

View File

@ -14,12 +14,9 @@ import com.flutter.gradle.FlutterPluginUtils.getAndroidExtension
import com.flutter.gradle.FlutterPluginUtils.getCompileSdkFromProject
import com.flutter.gradle.FlutterPluginUtils.supportsBuildMode
import com.flutter.gradle.NativePluginLoaderReflectionBridge
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.extraProperties
import java.io.File
import java.io.FileNotFoundException
import java.nio.charset.StandardCharsets
/**
* Handles interactions with the flutter plugins (not Gradle plugins) used by the Flutter project,
@ -75,82 +72,7 @@ class PluginHandler(
return pluginDependencies!!
}
// TODO(54566, 48918): Can remove once the issues are resolved.
// This means all references to `.flutter-plugins` are then removed and
// apps only depend exclusively on the `plugins` property in `.flutter-plugins-dependencies`.
/**
* Workaround to load non-native plugins for developers who may still use an
* old `settings.gradle` which includes all the plugins from the
* `.flutter-plugins` file, even if not made for Android.
* The settings.gradle then:
* 1) tries to add the android plugin implementation, which does not
* exist at all, but is also not included successfully
* (which does not throw an error and therefore isn't a problem), or
* 2) includes the plugin successfully as a valid android plugin
* directory exists, even if the surrounding flutter package does not
* support the android platform (see e.g. apple_maps_flutter: 1.0.1).
* So as it's included successfully it expects to be added as API.
* This is only possible by taking all plugins into account, which
* only appear on the `dependencyGraph` and in the `.flutter-plugins` file.
* So in summary the plugins are currently selected from the `dependencyGraph`
* and filtered then with the [pluginSupportsAndroidPlatform] method instead of
* just using the `plugins.android` list.
*/
private fun configureLegacyPluginEachProjects(engineVersionValue: String) {
try {
// Read the contents of the settings.gradle file.
// Remove block/line comments
var settingsText =
FlutterPluginUtils
.getSettingsGradleFileFromProjectDir(
project.projectDir,
project.logger
).readText(StandardCharsets.UTF_8)
settingsText =
settingsText
.replace(Regex("""(?s)/\*.*?\*/"""), "")
.replace(Regex("""(?m)//.*$"""), "")
if (!settingsText.contains("'.flutter-plugins'")) {
return
}
} catch (ignored: FileNotFoundException) {
throw GradleException(
"settings.gradle/settings.gradle.kts does not exist: " +
FlutterPluginUtils
.getSettingsGradleFileFromProjectDir(
project.projectDir,
project.logger
).absolutePath
)
}
// TODO(matanlurey): https://github.com/flutter/flutter/issues/48918.
project.logger.quiet(
legacyFlutterPluginsWarning
)
val deps: List<Map<String?, Any?>> = getPluginDependencies()
val pluginsNameSet = HashSet<String>()
getPluginList().mapTo(pluginsNameSet) { plugin -> plugin["name"] as String }
deps.filterNot { plugin -> pluginsNameSet.contains(plugin["name"]) }
deps.forEach { plugin: Map<String?, Any?> ->
val pluginProject = project.rootProject.findProject(":${plugin["name"]}")
if (pluginProject == null) {
// Plugin was not included in `settings.gradle`, but is listed in `.flutter-plugins`.
project.logger.error(
"Plugin project :${plugin["name"]} listed, but not found. Please fix your settings.gradle/settings.gradle.kts."
)
} else if (pluginSupportsAndroidPlatform(project)) {
// Plugin has a functioning `android` folder and is included successfully, although it's not supported.
// It must be configured nonetheless, to not throw an "Unresolved reference" exception.
configurePluginProject(project, plugin, engineVersionValue)
} else {
// Plugin has no or an empty `android` folder. No action required.
}
}
}
internal fun configurePlugins(engineVersionValue: String) {
configureLegacyPluginEachProjects(engineVersionValue)
val pluginList: List<Map<String?, Any?>> = getPluginList()
pluginList.forEach { plugin: Map<String?, Any?> ->
configurePluginProject(

View File

@ -326,118 +326,4 @@ class PluginHandlerTest {
)
}
}
@Test
fun `configurePlugins works for old flutter-plugins file`(
@TempDir tempDir: Path
) {
val project = mockk<Project>()
// configuration for configureLegacyPluginEachProjects
val projectDir = tempDir.resolve("my-plugin")
projectDir.toFile().mkdirs()
every { project.projectDir } returns projectDir.toFile()
val settingsGradle = File(projectDir.parent.toFile(), "settings.gradle")
settingsGradle.createNewFile()
settingsGradle.writeText("def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')")
val mockLogger = mockk<Logger>()
every { project.logger } returns mockLogger
every { mockLogger.quiet(any()) } returns Unit
val pluginProject = mockk<Project>()
val pluginDependencyProject = mockk<Project>()
val mockBuildType = mockk<com.android.build.gradle.internal.dsl.BuildType>()
every { pluginProject.hasProperty("local-engine-repo") } returns false
every { pluginProject.hasProperty("android") } returns true
every { mockBuildType.name } returns "debug"
every { mockBuildType.isDebuggable } returns true
every { project.rootProject.findProject(":${cameraDependency["name"]}") } returns pluginProject
every { project.rootProject.findProject(":${flutterPluginAndroidLifecycleDependency["name"]}") } returns pluginDependencyProject
every { pluginProject.extensions.create(any(), any<Class<Any>>()) } returns mockk()
val captureActionSlot = slot<Action<Project>>()
val capturePluginActionSlot = mutableListOf<Action<Project>>()
every { project.afterEvaluate(any<Action<Project>>()) } returns Unit
every { pluginProject.afterEvaluate(any<Action<Project>>()) } returns Unit
val mockProjectBuildTypes =
mockk<NamedDomainObjectContainer<com.android.build.gradle.internal.dsl.BuildType>>()
val mockPluginProjectBuildTypes =
mockk<NamedDomainObjectContainer<com.android.build.gradle.internal.dsl.BuildType>>()
every { project.extensions.findByType(BaseExtension::class.java)!!.buildTypes } returns mockProjectBuildTypes
every { pluginProject.extensions.findByType(BaseExtension::class.java)!!.buildTypes } returns mockPluginProjectBuildTypes
every { mockPluginProjectBuildTypes.addAll(any()) } returns true
every { pluginProject.configurations.named(any<String>()) } returns mockk()
every { pluginProject.dependencies.add(any(), any()) } returns mockk()
every {
project.extensions
.findByType(BaseExtension::class.java)!!
.buildTypes
.iterator()
} returns
mutableListOf(
mockBuildType
).iterator() andThen
mutableListOf( // can't return the same iterator as it is stateful
mockBuildType
).iterator() andThen
mutableListOf( // and again
mockBuildType
).iterator()
every { project.dependencies.add(any(), any()) } returns mockk()
every { project.extensions.findByType(BaseExtension::class.java)!!.compileSdkVersion } returns "android-35"
every { pluginProject.extensions.findByType(BaseExtension::class.java)!!.compileSdkVersion } returns "android-35"
val pluginHandler = PluginHandler(project)
mockkObject(NativePluginLoaderReflectionBridge)
// mock return of NativePluginLoaderReflectionBridge.getPlugins
val pluginWithDependencies: MutableMap<String?, Any?> = cameraDependency.toMutableMap()
pluginWithDependencies["dependencies"] =
listOf(flutterPluginAndroidLifecycleDependency["name"])
every { NativePluginLoaderReflectionBridge.getPlugins(any(), any()) } returns
listOf(
pluginWithDependencies
)
// mock method calls that are invoked by the args to NativePluginLoaderReflectionBridge.getPlugins
every { project.extraProperties } returns mockk()
every { project.extensions.findByType(FlutterExtension::class.java) } returns FlutterExtension()
every { project.file(any()) } returns mockk()
val dependencyGraph =
listOf<Map<String?, Any?>>(
mapOf(
"name" to cameraDependency["name"],
"dependencies" to listOf(flutterPluginAndroidLifecycleDependency["name"])
),
mapOf(
"name" to flutterPluginAndroidLifecycleDependency["name"],
"dependencies" to listOf<String>()
)
)
every { NativePluginLoaderReflectionBridge.getDependenciesMetadata(any(), any()) } returns
mapOf("dependencyGraph" to dependencyGraph)
pluginHandler.configurePlugins(
engineVersionValue = EXAMPLE_ENGINE_VERSION
)
verify { project.afterEvaluate(capture(captureActionSlot)) }
verify { pluginProject.afterEvaluate(capture(capturePluginActionSlot)) }
captureActionSlot.captured.execute(project)
capturePluginActionSlot[0].execute(pluginProject)
capturePluginActionSlot[1].execute(pluginProject)
verify { pluginProject.extensions.create("flutter", FlutterExtension::class.java) }
verify {
pluginProject.dependencies.add(
"debugApi",
"io.flutter:flutter_embedding_debug:$EXAMPLE_ENGINE_VERSION"
)
}
verify { project.dependencies.add("debugApi", pluginProject) }
verify { mockPluginProjectBuildTypes.addAll(project.extensions.findByType(BaseExtension::class.java)!!.buildTypes) }
verify { pluginProject.dependencies.add("implementation", pluginDependencyProject) }
verify { mockLogger.quiet(PluginHandler.legacyFlutterPluginsWarning) }
}
}