Skip to content

Commit fffbf66

Browse files
authored
Removes dev dependencies from generated plugin registrant for non-Android platforms (#161828)
Removes dev dependencies from the generated plugin registrants for all platforms since they will be removed from release builds (this was already done for Android, mostly in flutter/flutter#161343). Fixes flutter/flutter#161348. ## 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. <!-- 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
1 parent 1dd3f5d commit fffbf66

File tree

6 files changed

+255
-79
lines changed

6 files changed

+255
-79
lines changed

packages/flutter_tools/lib/src/flutter_plugins.dart

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -363,20 +363,11 @@ List<Map<String, Object?>> _extractPlatformMaps(Iterable<Plugin> plugins, String
363363
];
364364
}
365365

366-
Future<void> _writeAndroidPluginRegistrant(
367-
FlutterProject project,
368-
List<Plugin> plugins, {
369-
required bool releaseMode,
370-
}) async {
371-
Iterable<Plugin> methodChannelPlugins = _filterMethodChannelPlugins(
366+
Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
367+
final List<Plugin> methodChannelPlugins = _filterMethodChannelPlugins(
372368
plugins,
373369
AndroidPlugin.kConfigKey,
374370
);
375-
// TODO(camsim99): Remove dev dependencies from release builds for all platforms. See https://github.com/flutter/flutter/issues/161348.
376-
if (releaseMode) {
377-
methodChannelPlugins = methodChannelPlugins.where((Plugin p) => !p.isDevDependency);
378-
}
379-
380371
final List<Map<String, Object?>> androidPlugins = _extractPlatformMaps(
381372
methodChannelPlugins,
382373
AndroidPlugin.kConfigKey,
@@ -1204,7 +1195,7 @@ Future<void> injectBuildTimePluginFilesForWebPlatform(
12041195

12051196
/// Injects plugins found in `pubspec.yaml` into the platform-specific projects.
12061197
///
1207-
/// The injected files are required by the flutter app as soon as possible, so
1198+
/// The injected files are required by the Flutter app as soon as possible, so
12081199
/// it can be built.
12091200
///
12101201
/// Files written by this method end up in platform-specific locations that are
@@ -1225,18 +1216,19 @@ Future<void> injectPlugins(
12251216
DarwinDependencyManagement? darwinDependencyManagement,
12261217
bool? releaseMode,
12271218
}) async {
1228-
final List<Plugin> plugins = await findPlugins(project);
1219+
List<Plugin> plugins = await findPlugins(project);
1220+
1221+
if (releaseMode ?? false) {
1222+
plugins = plugins.where((Plugin p) => !p.isDevDependency).toList();
1223+
}
1224+
12291225
final Map<String, List<Plugin>> pluginsByPlatform = _resolvePluginImplementations(
12301226
plugins,
12311227
pluginResolutionType: _PluginResolutionType.nativeOrDart,
12321228
);
12331229

12341230
if (androidPlatform) {
1235-
await _writeAndroidPluginRegistrant(
1236-
project,
1237-
pluginsByPlatform[AndroidPlugin.kConfigKey]!,
1238-
releaseMode: releaseMode ?? false,
1239-
);
1231+
await _writeAndroidPluginRegistrant(project, pluginsByPlatform[AndroidPlugin.kConfigKey]!);
12401232
}
12411233
if (iosPlatform) {
12421234
await _writeIOSPluginRegistrant(project, pluginsByPlatform[IOSPlugin.kConfigKey]!);

packages/flutter_tools/lib/src/platform_plugins.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ class AndroidPlugin extends PluginPlatform implements NativeOrDartPlugin {
244244
/// The [name] of the plugin is required. Additionally, either:
245245
/// - [defaultPackage], or
246246
/// - an implementation consisting of:
247-
/// - the [pluginClass] (with optional [classPrefix]) that will be the entry
247+
/// - the [classPrefix] (with optional [pluginClass]) that will be the entry
248248
/// point to the plugin's native code, and/or
249249
/// - the [dartPluginClass] with optional [dartFileName] that will be
250250
/// the entry point for the plugin's Dart code

packages/flutter_tools/lib/src/project.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,18 @@ class AndroidProject extends FlutterProjectPlatform {
637637
return hostAppGradleRoot.childFile('AndroidManifest.xml');
638638
}
639639

640+
File get generatedPluginRegistrantFile {
641+
return hostAppGradleRoot
642+
.childDirectory('app')
643+
.childDirectory('src')
644+
.childDirectory('main')
645+
.childDirectory('java')
646+
.childDirectory('io')
647+
.childDirectory('flutter')
648+
.childDirectory('plugins')
649+
.childFile('GeneratedPluginRegistrant.java');
650+
}
651+
640652
File get gradleAppOutV1File => gradleAppOutV1Directory.childFile('app-debug.apk');
641653

642654
Directory get gradleAppOutV1Directory {

packages/flutter_tools/test/general.shard/plugins_test.dart

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2510,6 +2510,226 @@ The Flutter Preview device does not support the following plugins from your pubs
25102510
returnsNormally,
25112511
);
25122512
});
2513+
2514+
group('injectPlugins in release mode', () {
2515+
const String testPluginName = 'test_plugin';
2516+
2517+
// Fake pub to override dev dependencies of flutterProject.
2518+
final Pub fakePubWithTestPluginDevDependency = FakePubWithPrimedDeps(
2519+
devDependencies: <String>{testPluginName},
2520+
);
2521+
2522+
testUsingContext(
2523+
'excludes dev dependencies from Android plugin registrant',
2524+
() async {
2525+
final Directory pluginDir = createPlugin(
2526+
name: testPluginName,
2527+
platforms: const <String, _PluginPlatformInfo>{
2528+
'android': _PluginPlatformInfo(pluginClass: 'Foo', androidPackage: 'bar.foo'),
2529+
},
2530+
);
2531+
2532+
// injectPlugins will fail if main native class not found in expected spot, so add
2533+
// it first.
2534+
pluginDir
2535+
.childDirectory('android')
2536+
.childDirectory('src')
2537+
.childDirectory('main')
2538+
.childDirectory('java')
2539+
.childDirectory('bar')
2540+
.childDirectory('foo')
2541+
.childFile('Foo.java')
2542+
..createSync(recursive: true)
2543+
..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin;');
2544+
2545+
// Test non-release mode.
2546+
await injectPlugins(flutterProject, androidPlatform: true, releaseMode: false);
2547+
final File generatedPluginRegistrant =
2548+
flutterProject.android.generatedPluginRegistrantFile;
2549+
expect(generatedPluginRegistrant, exists);
2550+
expect(generatedPluginRegistrant.readAsStringSync(), contains('bar.foo.Foo'));
2551+
2552+
// Test release mode.
2553+
await injectPlugins(flutterProject, androidPlatform: true, releaseMode: true);
2554+
expect(generatedPluginRegistrant, exists);
2555+
expect(generatedPluginRegistrant.readAsStringSync(), isNot(contains('bar.foo.Foo')));
2556+
},
2557+
overrides: <Type, Generator>{
2558+
FileSystem: () => fs,
2559+
ProcessManager: () => FakeProcessManager.any(),
2560+
FeatureFlags: enableExplicitPackageDependencies,
2561+
Pub: () => fakePubWithTestPluginDevDependency,
2562+
},
2563+
);
2564+
2565+
testUsingContext(
2566+
'excludes dev dependencies from iOS plugin registrant',
2567+
() async {
2568+
createPlugin(
2569+
name: testPluginName,
2570+
platforms: const <String, _PluginPlatformInfo>{
2571+
'ios': _PluginPlatformInfo(pluginClass: 'Foo'),
2572+
},
2573+
);
2574+
2575+
final FakeDarwinDependencyManagement dependencyManagement =
2576+
FakeDarwinDependencyManagement();
2577+
const String devDepImport = '#import <$testPluginName/Foo.h>';
2578+
2579+
// Test non-release mode.
2580+
await injectPlugins(
2581+
flutterProject,
2582+
iosPlatform: true,
2583+
darwinDependencyManagement: dependencyManagement,
2584+
releaseMode: false,
2585+
);
2586+
final File generatedPluginRegistrantImpl =
2587+
flutterProject.ios.pluginRegistrantImplementation;
2588+
expect(generatedPluginRegistrantImpl, exists);
2589+
expect(generatedPluginRegistrantImpl.readAsStringSync(), contains(devDepImport));
2590+
2591+
// Test release mode.
2592+
await injectPlugins(
2593+
flutterProject,
2594+
iosPlatform: true,
2595+
darwinDependencyManagement: dependencyManagement,
2596+
releaseMode: true,
2597+
);
2598+
expect(generatedPluginRegistrantImpl, exists);
2599+
expect(generatedPluginRegistrantImpl.readAsStringSync(), isNot(contains(devDepImport)));
2600+
},
2601+
overrides: <Type, Generator>{
2602+
FileSystem: () => fs,
2603+
ProcessManager: () => FakeProcessManager.any(),
2604+
FeatureFlags: enableExplicitPackageDependencies,
2605+
Pub: () => fakePubWithTestPluginDevDependency,
2606+
},
2607+
);
2608+
2609+
testUsingContext(
2610+
'excludes dev dependencies from Linux plugin registrant',
2611+
() async {
2612+
createPlugin(
2613+
name: testPluginName,
2614+
platforms: const <String, _PluginPlatformInfo>{
2615+
'linux': _PluginPlatformInfo(pluginClass: 'Foo'),
2616+
},
2617+
);
2618+
2619+
const String expectedDevDepImport = '#include <$testPluginName/foo.h>';
2620+
2621+
// Test non-release mode.
2622+
await injectPlugins(flutterProject, linuxPlatform: true, releaseMode: false);
2623+
final File generatedPluginRegistrant = flutterProject.linux.managedDirectory.childFile(
2624+
'generated_plugin_registrant.cc',
2625+
);
2626+
expect(generatedPluginRegistrant, exists);
2627+
expect(generatedPluginRegistrant.readAsStringSync(), contains(expectedDevDepImport));
2628+
2629+
// Test release mode.
2630+
await injectPlugins(flutterProject, linuxPlatform: true, releaseMode: true);
2631+
expect(generatedPluginRegistrant, exists);
2632+
expect(
2633+
generatedPluginRegistrant.readAsStringSync(),
2634+
isNot(contains(expectedDevDepImport)),
2635+
);
2636+
},
2637+
overrides: <Type, Generator>{
2638+
FileSystem: () => fs,
2639+
ProcessManager: () => FakeProcessManager.any(),
2640+
FeatureFlags: enableExplicitPackageDependencies,
2641+
Pub: () => fakePubWithTestPluginDevDependency,
2642+
},
2643+
);
2644+
2645+
testUsingContext(
2646+
'excludes dev dependencies from MacOS plugin registrant',
2647+
() async {
2648+
createPlugin(
2649+
name: testPluginName,
2650+
platforms: const <String, _PluginPlatformInfo>{
2651+
'macos': _PluginPlatformInfo(pluginClass: 'Foo'),
2652+
},
2653+
);
2654+
final FakeDarwinDependencyManagement dependencyManagement =
2655+
FakeDarwinDependencyManagement();
2656+
const String expectedDevDepRegistration = 'Foo.register';
2657+
2658+
// Test non-release mode.
2659+
await injectPlugins(
2660+
flutterProject,
2661+
macOSPlatform: true,
2662+
darwinDependencyManagement: dependencyManagement,
2663+
releaseMode: false,
2664+
);
2665+
final File generatedPluginRegistrant = flutterProject.macos.managedDirectory.childFile(
2666+
'GeneratedPluginRegistrant.swift',
2667+
);
2668+
expect(generatedPluginRegistrant, exists);
2669+
expect(
2670+
generatedPluginRegistrant.readAsStringSync(),
2671+
contains(expectedDevDepRegistration),
2672+
);
2673+
2674+
// Test release mode.
2675+
await injectPlugins(
2676+
flutterProject,
2677+
macOSPlatform: true,
2678+
darwinDependencyManagement: dependencyManagement,
2679+
releaseMode: true,
2680+
);
2681+
expect(generatedPluginRegistrant, exists);
2682+
expect(
2683+
generatedPluginRegistrant.readAsStringSync(),
2684+
isNot(contains(expectedDevDepRegistration)),
2685+
);
2686+
},
2687+
overrides: <Type, Generator>{
2688+
FileSystem: () => fs,
2689+
ProcessManager: () => FakeProcessManager.any(),
2690+
FeatureFlags: enableExplicitPackageDependencies,
2691+
Pub: () => fakePubWithTestPluginDevDependency,
2692+
},
2693+
);
2694+
2695+
testUsingContext(
2696+
'excludes dev dependencies from Windows plugin registrant',
2697+
() async {
2698+
createPlugin(
2699+
name: testPluginName,
2700+
platforms: const <String, _PluginPlatformInfo>{
2701+
'windows': _PluginPlatformInfo(pluginClass: 'Foo'),
2702+
},
2703+
);
2704+
2705+
const String expectedDevDepRegistration = '#include <$testPluginName/foo.h>';
2706+
2707+
// Test non-release mode.
2708+
await injectPlugins(flutterProject, windowsPlatform: true, releaseMode: false);
2709+
final File generatedPluginRegistrantImpl = flutterProject.windows.managedDirectory
2710+
.childFile('generated_plugin_registrant.cc');
2711+
expect(generatedPluginRegistrantImpl, exists);
2712+
expect(
2713+
generatedPluginRegistrantImpl.readAsStringSync(),
2714+
contains(expectedDevDepRegistration),
2715+
);
2716+
2717+
// Test release mode.
2718+
await injectPlugins(flutterProject, windowsPlatform: true, releaseMode: true);
2719+
expect(generatedPluginRegistrantImpl, exists);
2720+
expect(
2721+
generatedPluginRegistrantImpl.readAsStringSync(),
2722+
isNot(contains(expectedDevDepRegistration)),
2723+
);
2724+
},
2725+
overrides: <Type, Generator>{
2726+
FileSystem: () => fs,
2727+
ProcessManager: () => FakeProcessManager.any(),
2728+
FeatureFlags: enableExplicitPackageDependencies,
2729+
Pub: () => fakePubWithTestPluginDevDependency,
2730+
},
2731+
);
2732+
});
25132733
});
25142734

25152735
testUsingContext(
@@ -2718,6 +2938,17 @@ class FakeAndroidProject extends Fake implements AndroidProject {
27182938
AndroidEmbeddingVersionResult computeEmbeddingVersion() {
27192939
return AndroidEmbeddingVersionResult(embeddingVersion, 'reasons for version');
27202940
}
2941+
2942+
@override
2943+
File get generatedPluginRegistrantFile => hostAppGradleRoot
2944+
.childDirectory('app')
2945+
.childDirectory('src')
2946+
.childDirectory('main')
2947+
.childDirectory('java')
2948+
.childDirectory('io')
2949+
.childDirectory('flutter')
2950+
.childDirectory('plugins')
2951+
.childFile('GeneratedPluginRegistrant.java');
27212952
}
27222953

27232954
class FakeWebProject extends Fake implements WebProject {

packages/flutter_tools/test/general.shard/windows/plugins_test.dart

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

packages/flutter_tools/test/src/fake_pub_deps.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ final class FakePubWithPrimedDeps implements Pub {
2727
'name': rootPackageName,
2828
'kind': 'root',
2929
'dependencies': <String>[...dependencies.keys, ...devDependencies]..sort(),
30-
'directDependencies': <String>[...?dependencies[rootPackageName], ...devDependencies]
31-
..sort(),
30+
'directDependencies': <String>[...?dependencies[rootPackageName]]..sort(),
3231
'devDependencies': <String>[...devDependencies],
3332
},
3433
];

0 commit comments

Comments
 (0)