.flutter-plugins-dependencies replaces .flutter-plugins.

Summary

#

The flutter tool will no longer output the legacy .flutter-plugins metadata file, and only output .flutter-plugins-dependencies. Tools and build scripts, such as Gradle configurations (for Android apps) that rely on the presence of .flutter-plugins will need to be updated.

Background

#

In 2019 .flutter-plugins-dependencies was added as a newer file format that replaces .flutter-plugins.

So a file that looked something like this:

txt
# This is .flutter-plugins
camera=/path/to/camera/plugin
shared_preferences=shared_preferences

... was replaced by something like this:

json
{
  "dependencyGraph": {
    "camera": {
      "name": "camera",
      "version": "0.10.0",
      "dependencies": {
        "flutter": "0.0.0"
      }
    },
    "shared_preferences": {
      "name": "shared_preferences",
      "version": "2.0.15",
      "dependencies": {
        "flutter": "0.0.0"
      }
    }
  },
  "flutter": {
    "frameworkRevision": "3a0f99d4f2",
    "channel": "stable"
  }
}

Having both files output is a source of technical debt that complicates new feature sets like not bundling dev_dependency plugins in a release app.

Migration guide

#

Most Flutter developers don't parse or use this file, but build configurations (such as settings.gradle), as generated by older invocations of flutter create --platforms android. These legacy files might still reference .flutter-plugins and must be updated to a newer build script.

For example:

groovy
include ':app'

def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()

def plugins = new Properties()
// Note explicitly reading the legacy '.flutter-plugins' file.
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}

plugins.each { name, path ->
    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
    include ":$name"
    project(":$name").projectDir = pluginDirectory
}

... might be upgraded to its settings.gradle.kts equivalent:

kts
pluginManagement {
    val flutterSdkPath = run {
        val properties = java.util.Properties()
        file("local.properties").inputStream().use { properties.load(it) }
        val flutterSdkPath = properties.getProperty("flutter.sdk")
        require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
        flutterSdkPath
    }

    includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")

    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

plugins {
    // Note the use of the flutter-plugin-loader versus reading '.flutter-plugins'
    id("dev.flutter.flutter-plugin-loader") version "1.0.0"
    id("com.android.application") version "8.1.0" apply false
    id("org.jetbrains.kotlin.android") version "1.8.22" apply false
}

include(":app")

See Deprecated imperative apply of Flutter's Gradle plugins for details of switching to the newer plugin DSL.

To smoke test whether your build relies on a .flutter-plugins file, you can use the flag --no-implicit-pubspec-resolution:

sh
flutter build apk --no-implicit-pubspec-resolution

Any build tools or scripts that might rely on that file being output will now fail.

Timeline

#

Not released

Not released + 1, .flutter-plugins support will be removed.

References

#

Relevant Issues:

  • Issue 48918, where .flutter-plugins was (in 2020) slated for deprecation.

Relevant PRs:

  • PR 45379, where .flutter-plugins-dependencies was originally added.
  • PR 157388, where a warning was adding to the Flutter Android build scripts.