[Android] Actually remove dev dependencies from release builds (#161343)

Revises https://github.com/flutter/flutter/pull/158026 to fix
https://github.com/flutter/flutter/issues/160407.

Makes a number of fixes:

- Fixes Groovy logic that attempted to remove dev dependencies from
release builds to use `<buildType>Api` versus `api` and loop to
configure the project dependencies per build type
- Adds back dependency on embedding to plugin projects since this is
needed regardless (the plugin may not be included in a particularly
typed build but it still needs it for where it's included)
- Fixes integration test to throw and error upon failure, check right
APK for the release build it's testing, and configure the flag need for
`.flutter-plugin-dependencies` to mark plugins as dev dependencies as
expected
- Uses @matanlurey's
[patch](https://github.com/flutter/flutter/issues/160407#issuecomment-2547546038)
to remove dev dependency from the `GeneratedPluginRegistrant` in release
mode

## 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.
- [ ] All existing and new tests are passing.

<!-- 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
This commit is contained in:
Camille Simon 2025-01-14 13:36:52 -06:00 committed by GitHub
parent 0369b35640
commit 818133b8b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 37 additions and 20 deletions

View File

@ -15,6 +15,9 @@ Future<void> main() async {
await task(() async {
try {
await runProjectTest((FlutterProject flutterProject) async {
// Enable plugins being marked as dev dependncies in the .flutter-plugins-dependencies file.
await flutter('config', options: <String>['--explicit-package-dependencies']);
// Create dev_dependency plugin to use for test.
final Directory tempDir = Directory.systemTemp.createTempSync(
'android_release_builds_exclude_dev_dependencies_test.',
@ -50,7 +53,7 @@ Future<void> main() async {
'app',
'outputs',
'flutter-apk',
'app-debug.apk',
'app-$buildMode.apk',
),
);
if (!apk.existsSync()) {
@ -66,7 +69,7 @@ Future<void> main() async {
final bool apkIncludesDevDependencyAsExpected =
isTestingReleaseMode ? !apkIncludesDevDependency : apkIncludesDevDependency;
if (!apkIncludesDevDependencyAsExpected) {
return TaskResult.failure(
throw TaskResult.failure(
'Expected to${isTestingReleaseMode ? ' not' : ''} find dev_dependency_plugin in APK built with debug mode but did${isTestingReleaseMode ? '' : ' not'}.',
);
}

View File

@ -738,13 +738,12 @@ class FlutterPlugin implements Plugin<Project> {
// 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)
// Add plugin dependency to the app project. We only want to add dependency
// for dev dependencies in non-release builds.
project.afterEvaluate {
project.android.buildTypes.all { buildType ->
if (!pluginObject.dev_dependency || buildType.name != 'release') {
project.dependencies.add("${buildType.name}Api", pluginProject)
}
}
}
@ -760,12 +759,6 @@ class FlutterPlugin implements Plugin<Project> {
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 {

View File

@ -356,18 +356,27 @@ public final class GeneratedPluginRegistrant {
}
''';
List<Map<String, Object?>> _extractPlatformMaps(List<Plugin> plugins, String type) {
List<Map<String, Object?>> _extractPlatformMaps(Iterable<Plugin> plugins, String type) {
return <Map<String, Object?>>[
for (final Plugin plugin in plugins)
if (plugin.platforms[type] case final PluginPlatform platformPlugin) platformPlugin.toMap(),
];
}
Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
final List<Plugin> methodChannelPlugins = _filterMethodChannelPlugins(
Future<void> _writeAndroidPluginRegistrant(
FlutterProject project,
List<Plugin> plugins, {
required bool releaseMode,
}) async {
Iterable<Plugin> methodChannelPlugins = _filterMethodChannelPlugins(
plugins,
AndroidPlugin.kConfigKey,
);
// TODO(camsim99): Remove dev dependencies from release builds for all platforms. See https://github.com/flutter/flutter/issues/161348.
if (releaseMode) {
methodChannelPlugins = methodChannelPlugins.where((Plugin p) => !p.isDevDependency);
}
final List<Map<String, Object?>> androidPlugins = _extractPlatformMaps(
methodChannelPlugins,
AndroidPlugin.kConfigKey,
@ -1214,6 +1223,7 @@ Future<void> injectPlugins(
bool windowsPlatform = false,
Iterable<String>? allowedPlugins,
DarwinDependencyManagement? darwinDependencyManagement,
bool? releaseMode,
}) async {
final List<Plugin> plugins = await findPlugins(project);
final Map<String, List<Plugin>> pluginsByPlatform = _resolvePluginImplementations(
@ -1222,7 +1232,11 @@ Future<void> injectPlugins(
);
if (androidPlatform) {
await _writeAndroidPluginRegistrant(project, pluginsByPlatform[AndroidPlugin.kConfigKey]!);
await _writeAndroidPluginRegistrant(
project,
pluginsByPlatform[AndroidPlugin.kConfigKey]!,
releaseMode: releaseMode ?? false,
);
}
if (iosPlatform) {
await _writeIOSPluginRegistrant(project, pluginsByPlatform[IOSPlugin.kConfigKey]!);

View File

@ -332,6 +332,7 @@ class FlutterProject {
Future<void> regeneratePlatformSpecificTooling({
DeprecationBehavior deprecationBehavior = DeprecationBehavior.none,
Iterable<String>? allowedPlugins,
bool? releaseMode,
}) async {
return ensureReadyForPlatformSpecificTooling(
androidPlatform: android.existsSync(),
@ -344,6 +345,7 @@ class FlutterProject {
webPlatform: featureFlags.isWebEnabled && web.existsSync(),
deprecationBehavior: deprecationBehavior,
allowedPlugins: allowedPlugins,
releaseMode: releaseMode,
);
}
@ -358,6 +360,7 @@ class FlutterProject {
bool webPlatform = false,
DeprecationBehavior deprecationBehavior = DeprecationBehavior.none,
Iterable<String>? allowedPlugins,
bool? releaseMode,
}) async {
if (!directory.existsSync() || isPlugin) {
return;
@ -389,6 +392,7 @@ class FlutterProject {
macOSPlatform: macOSPlatform,
windowsPlatform: windowsPlatform,
allowedPlugins: allowedPlugins,
releaseMode: releaseMode,
);
}

View File

@ -1907,7 +1907,10 @@ Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and
// The preview device does not currently support any plugins.
allowedPlugins = PreviewDevice.supportedPubPlugins;
}
await project.regeneratePlatformSpecificTooling(allowedPlugins: allowedPlugins);
await project.regeneratePlatformSpecificTooling(
allowedPlugins: allowedPlugins,
releaseMode: featureFlags.isExplicitPackageDependenciesEnabled && getBuildMode().isRelease,
);
if (reportNullSafety) {
await _sendNullSafetyAnalyticsEvents(project);
}