Repository navigation
flutter config --explicit-package-dependencies breaks flutter build apk #160407
Description
Looking at the failures still being flagged in #160289, I see a trend where flutter build apk (which implicitly is release mode) causes the integration_test package itself to fail to be built (example); I'm guessing that when we short-circuit the build, we're still leaving artifacts that integration_test is depended on, but not in a way that compilation succeeds.
Reproduces at HEAD:
# Opt-in to the feature
flutter config --explicit-package-dependencies
# Create an Android plugin
flutter create plugin_a --template=plugin --platforms=android
# Try to build the example app for the plugin
cd plugin_a/example
flutter build apkBy opting-out again (flutter config --no-explicit-package-dependencies) the build succeeds.
Interestingly, the integration test for this feature does do a flutter build apk --release, so I'm guessing this has something to do with how integration_test imports and uses the Android embedder (i.e. import io.flutter.embedding.android.FlutterActivity and like), and the default (empty) plugin template does not - we should add a regression test as part of fixing this.
Some potentially useful bits:
With the flag enabled, .flutter-plugins-dependencies looks like this
{
"info": "This is a generated file; do not edit or check into version control.",
"plugins": {
"ios": [
{
"name": "integration_test",
"path": "/Users/matanl/Developer/flutter/packages/integration_test/",
"native_build": true,
"dependencies": [],
"dev_dependency": true
}
],
"android": [
{
"name": "integration_test",
"path": "/Users/matanl/Developer/flutter/packages/integration_test/",
"native_build": true,
"dependencies": [],
"dev_dependency": true
},
{
"name": "plugin_a",
"path": "/private/tmp/flutter.tmp/plugin_a/",
"native_build": true,
"dependencies": [],
"dev_dependency": false
}
],
"macos": [],
"linux": [],
"windows": [],
"web": []
},
"dependencyGraph": [
{
"name": "integration_test",
"dependencies": []
},
{
"name": "plugin_a",
"dependencies": []
}
],
"date_created": "2024-12-16 20:52:06.884223",
"version": "3.28.0-1.0.pre.157",
"swift_package_manager_enabled": {
"ios": false,
"macos": false
}
}Here is what plugin_a/pubspec.yaml looks like
dependencies:
flutter:
sdk: flutter
plugin_a:
# When depending on this package from a real application you should use:
# plugin_a: ^x.y.z
# See https://dart.dev/tools/pub/dependencies#version-constraints
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
dev_dependencies:
integration_test:
sdk: flutter
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^5.0.0I assume it's further work required in flutter.groovy:
flutter/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy
Lines 764 to 829 in 27ef196
| private void configurePluginProject(Map<String, Object> pluginObject) { | |
| assert(pluginObject.name instanceof String) | |
| Project pluginProject = project.rootProject.findProject(":${pluginObject.name}") | |
| if (pluginProject == null) { | |
| return | |
| } | |
| // Apply the "flutter" Gradle extension to plugins so that they can use it's vended | |
| // compile/target/min sdk values. | |
| pluginProject.extensions.create("flutter", FlutterExtension) | |
| // Add plugin dependency to the app project. | |
| project.android.buildTypes.each { buildType -> | |
| String flutterBuildMode = buildModeFor(buildType) | |
| if (flutterBuildMode != "release" || !pluginObject.dev_dependency) { | |
| // Only add dependency on dev dependencies in non-release builds. | |
| project.dependencies { | |
| api(pluginProject) | |
| } | |
| } | |
| } | |
| Closure addEmbeddingDependencyToPlugin = { buildType -> | |
| String flutterBuildMode = buildModeFor(buildType) | |
| // In AGP 3.5, the embedding must be added as an API implementation, | |
| // so java8 features are desugared against the runtime classpath. | |
| // For more, see https://github.com/flutter/flutter/issues/40126 | |
| if (!supportsBuildMode(flutterBuildMode)) { | |
| return | |
| } | |
| if (!pluginProject.hasProperty("android")) { | |
| return | |
| } | |
| if (flutterBuildMode == "release" && pluginObject.dev_dependency) { | |
| // This plugin is a dev dependency and will not be included in | |
| // the release build, so no need to add the embedding | |
| // dependency to it. | |
| return | |
| } | |
| // Copy build types from the app to the plugin. | |
| // This allows to build apps with plugins and custom build types or flavors. | |
| pluginProject.android.buildTypes { | |
| "${buildType.name}" {} | |
| } | |
| // The embedding is API dependency of the plugin, so the AGP is able to desugar | |
| // default method implementations when the interface is implemented by a plugin. | |
| // | |
| // See https://issuetracker.google.com/139821726, and | |
| // https://github.com/flutter/flutter/issues/72185 for more details. | |
| addApiDependencies( | |
| pluginProject, | |
| buildType.name, | |
| "io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion" | |
| ) | |
| } | |
| // Wait until the Android plugin loaded. | |
| pluginProject.afterEvaluate { | |
| // Checks if there is a mismatch between the plugin compileSdkVersion and the project compileSdkVersion. | |
| if (pluginProject.android.compileSdkVersion > project.android.compileSdkVersion) { | |
| project.logger.quiet("Warning: The plugin ${pluginObject.name} requires Android SDK version ${getCompileSdkFromProject(pluginProject)} or higher.") | |
| project.logger.quiet("For more information about build configuration, see $kWebsiteDeploymentAndroidBuildConfig.") | |
| } | |
| project.android.buildTypes.all(addEmbeddingDependencyToPlugin) | |
| } | |
| } |
Activity
[-]Enabling `flutter config --explicit-package-dependencies` breaks release compilation[/-][+]`flutter config --explicit-package-dependencies` breaks `flutter build apk`[/+]matanlurey commentedon Dec 17, 2024
Oh, you know what it is... we don't strip out the import in
GeneratedPluginRegistrant.java:matanlurey commentedon Dec 17, 2024
Hmm, that wasn't sufficient - I threw together this patch and there are still the same compilation errors:
camsim99 commentedon Dec 20, 2024
Started digging into this and here's what I know:
flutter/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy
Lines 796 to 801 in 188d1e1
flutter build apk, the Flutter Gradle plugin configures plugins and their dependencies for debug and release builds (this might just be how apks are built? still trying to determine that)What I've been trying to dig into now is:
flutter build apk. I want to know the exact Gradle tasks it runs because it may be possibly my integration test did work and there are some tasks that still require compiling a plugin project though it won't be included in the final APK. I think this is less likely, so I think I'll spend most of my time now looking into...flutter/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy
Line 986 in 188d1e1
camsim99 commentedon Dec 23, 2024
I now suspect that the issue was an oopsie on my part. We ideally want the app project to only depend on the dev dependency if it is a release build. I tried doing this in
flutter/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy
Lines 775 to 783 in 5c7d9d0
but I don't think that actually works 😅 Need to figure out how to do something similar to
api(...)but only for release builds.Side note:
./gradlew :app:dependencies --configuration releaseRuntimeClasspathhas been helpful visualizing the dependency graph of what's include in the release APK.jmagman commentedon Dec 23, 2024
Are tests not runnable in release mode?
camsim99 commentedon Dec 23, 2024
Basically no when my featured is enabled and if the test depends on ‘integration_test’. Or at least that’s what @matanlurey has found so far is my understanding.
camsim99 commentedon Dec 23, 2024
Tried using
debugApiand this did remove it from the graph printed by./gradlew :app:dependencies --configuration releaseRuntimeClasspathbut I still get the same error...Note to self that I had to apply Matan's patch to modify the test plugin's example app's
GeneratedPluginRegistrant.java.camsim99 commentedon Jan 8, 2025
I think I've found a solution and will follow up with a PR shortly.
TLDR is that there were a couple of issues:
throwTaskResults in order to make the test fail, and (2) I was always checking the debug APK instead of the APK based on the build type I was testing.<buildType>Apimethods to configure dependencies per build type; the logic I wrote before was wrong, as I suspected.matanlurey commentedon Jan 8, 2025
Nice find! It would be really good to get this fixed before the branch cut, as otherwise it will take another quarter to flip
--explicit-package-dependencies.camsim99 commentedon Jan 8, 2025
Oop! Ok there's a tiny detail I'm not 100% sure about but I'll put up a PR right now and we can discuss there.
camsim99 commentedon Jan 8, 2025
Quick notes that I forgot: also the plugin does still need the embedding dependency, that is irrelevant to it being included in a build. Also I needed Matan's patch to fix the generated plugin registrant. And the integration test needs to use the
--explicit-package-dependenciesflag for now :)[Android] Actually remove dev dependencies from release builds (#161343)
[Android] Actually remove dev dependencies from release builds (flutt…
github-actions commentedon Jan 28, 2025
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.