Skip to content

Commit d932115

Browse files
authored
[tool] Add dartFileName setting for platform plugins (flutter#153099)
This PR introduces the `dartFileName` parameter for platform plugin configurations with Dart platform implementations. This new parameter allows plugin developers to specify a custom path to the file where the `dartPluginClass` is defined. **Implementation is opt-in**. `dartFileName` is completely optional and is taken in account only with `dartClassName`. Possibility to set `dartClassName` without `dartFileName` remains. **Implementation is backward compatible** � existing configurations using only `dartClassName` remain fully supported. If `dartFileName` is omitted, the system falls back to the previous behavior of deriving the file name from the plugin name. ## Example ```yaml flutter: plugin: platforms: some_platform: dartPluginClass: MyPlugin dartFileName: 'src/my_plugin_implementation.dart' ``` fixes flutter#152833
1 parent 9d9ec70 commit d932115

File tree

7 files changed

+364
-63
lines changed

7 files changed

+364
-63
lines changed

packages/flutter_tools/lib/src/flutter_plugins.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -624,19 +624,19 @@ const String _dartPluginRegistryForNonWebTemplate = '''
624624
625625
import 'dart:io'; // flutter_ignore: dart_io_import.
626626
{{#android}}
627-
import 'package:{{pluginName}}/{{pluginName}}.dart';
627+
import 'package:{{pluginName}}/{{dartFileName}}';
628628
{{/android}}
629629
{{#ios}}
630-
import 'package:{{pluginName}}/{{pluginName}}.dart';
630+
import 'package:{{pluginName}}/{{dartFileName}}';
631631
{{/ios}}
632632
{{#linux}}
633-
import 'package:{{pluginName}}/{{pluginName}}.dart';
633+
import 'package:{{pluginName}}/{{dartFileName}}';
634634
{{/linux}}
635635
{{#macos}}
636-
import 'package:{{pluginName}}/{{pluginName}}.dart';
636+
import 'package:{{pluginName}}/{{dartFileName}}';
637637
{{/macos}}
638638
{{#windows}}
639-
import 'package:{{pluginName}}/{{pluginName}}.dart';
639+
import 'package:{{pluginName}}/{{dartFileName}}';
640640
{{/windows}}
641641
642642
@pragma('vm:entry-point')
@@ -1432,8 +1432,8 @@ bool _hasPluginInlineImpl(
14321432

14331433
/// Determine if the plugin provides an inline Dart implementation.
14341434
bool _hasPluginInlineDartImpl(Plugin plugin, String platformKey) {
1435-
return plugin.pluginDartClassPlatforms[platformKey] != null &&
1436-
plugin.pluginDartClassPlatforms[platformKey] != 'none';
1435+
final DartPluginClassAndFilePair? platformInfo = plugin.pluginDartClassPlatforms[platformKey];
1436+
return platformInfo != null && platformInfo.dartClass != 'none';
14371437
}
14381438

14391439
/// Get the resolved plugin [resolution] from the [candidates] serving as implementation for

packages/flutter_tools/lib/src/platform_plugins.dart

Lines changed: 130 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ const String kPluginClass = 'pluginClass';
1313
/// Constant for 'dartPluginClass' key in plugin maps.
1414
const String kDartPluginClass = 'dartPluginClass';
1515

16+
/// Constant for 'dartPluginFile' key in plugin maps.
17+
const String kDartFileName = 'dartFileName';
18+
1619
/// Constant for 'ffiPlugin' key in plugin maps.
1720
const String kFfiPlugin = 'ffiPlugin';
1821

@@ -68,8 +71,8 @@ abstract class DarwinPlugin {
6871
/// - an implementation consisting of:
6972
/// - the [package] and [pluginClass] that will be the entry point to the
7073
/// plugin's native code, and/or
71-
/// - the [dartPluginClass] that will be the entry point for the plugin's
72-
/// Dart code
74+
/// - the [dartPluginClass] with optional [dartFileName] that will be
75+
/// the entry point for the plugin's Dart code
7376
/// is required.
7477
class AndroidPlugin extends PluginPlatform implements NativeOrDartPlugin {
7578
AndroidPlugin({
@@ -78,20 +81,40 @@ class AndroidPlugin extends PluginPlatform implements NativeOrDartPlugin {
7881
this.package,
7982
this.pluginClass,
8083
this.dartPluginClass,
84+
this.dartFileName,
8185
bool? ffiPlugin,
8286
this.defaultPackage,
8387
required FileSystem fileSystem,
8488
}) : _fileSystem = fileSystem,
8589
ffiPlugin = ffiPlugin ?? false;
8690

87-
AndroidPlugin.fromYaml(this.name, YamlMap yaml, this.pluginPath, FileSystem fileSystem)
88-
: assert(validate(yaml)),
89-
package = yaml['package'] as String?,
90-
pluginClass = yaml[kPluginClass] as String?,
91-
dartPluginClass = yaml[kDartPluginClass] as String?,
92-
ffiPlugin = yaml[kFfiPlugin] as bool? ?? false,
93-
defaultPackage = yaml[kDefaultPackage] as String?,
94-
_fileSystem = fileSystem;
91+
factory AndroidPlugin.fromYaml(
92+
String name,
93+
YamlMap yaml,
94+
String pluginPath,
95+
FileSystem fileSystem,
96+
) {
97+
assert(validate(yaml));
98+
99+
final String? dartPluginClass = yaml[kDartPluginClass] as String?;
100+
final String? dartFileName = yaml[kDartFileName] as String?;
101+
102+
if (dartPluginClass == null && dartFileName != null) {
103+
throw throwToolExit('"dartFileName" cannot be specified without "dartPluginClass" in Android platform of plugin "$name"');
104+
}
105+
106+
return AndroidPlugin(
107+
name: name,
108+
package: yaml['package'] as String?,
109+
pluginClass: yaml[kPluginClass] as String?,
110+
dartPluginClass: dartPluginClass,
111+
dartFileName: dartFileName,
112+
ffiPlugin: yaml[kFfiPlugin] as bool? ?? false,
113+
defaultPackage: yaml[kDefaultPackage] as String?,
114+
pluginPath: pluginPath,
115+
fileSystem: fileSystem,
116+
);
117+
}
95118

96119
final FileSystem _fileSystem;
97120

@@ -125,6 +148,9 @@ class AndroidPlugin extends PluginPlatform implements NativeOrDartPlugin {
125148
/// The Dart plugin main class defined in pubspec.yaml, if any.
126149
final String? dartPluginClass;
127150

151+
/// Path to file in which dartPluginClass defined, if any.
152+
final String? dartFileName;
153+
128154
/// Is FFI plugin defined in pubspec.yaml.
129155
final bool ffiPlugin;
130156

@@ -141,6 +167,7 @@ class AndroidPlugin extends PluginPlatform implements NativeOrDartPlugin {
141167
if (package != null) 'package': package,
142168
if (pluginClass != null) 'class': pluginClass,
143169
if (dartPluginClass != null) kDartPluginClass : dartPluginClass,
170+
if (dartFileName != null) kDartFileName: dartFileName,
144171
if (ffiPlugin) kFfiPlugin: true,
145172
if (defaultPackage != null) kDefaultPackage : defaultPackage,
146173
// Mustache doesn't support complex types.
@@ -224,29 +251,43 @@ class AndroidPlugin extends PluginPlatform implements NativeOrDartPlugin {
224251
/// - an implementation consisting of:
225252
/// - the [pluginClass] (with optional [classPrefix]) that will be the entry
226253
/// point to the plugin's native code, and/or
227-
/// - the [dartPluginClass] that will be the entry point for the plugin's
228-
/// Dart code
254+
/// - the [dartPluginClass] with optional [dartFileName] that will be
255+
/// the entry point for the plugin's Dart code
229256
/// is required.
230257
class IOSPlugin extends PluginPlatform implements NativeOrDartPlugin, DarwinPlugin {
231258
const IOSPlugin({
232259
required this.name,
233260
required this.classPrefix,
234261
this.pluginClass,
235262
this.dartPluginClass,
263+
this.dartFileName,
236264
bool? ffiPlugin,
237265
this.defaultPackage,
238266
bool? sharedDarwinSource,
239267
}) : ffiPlugin = ffiPlugin ?? false,
240268
sharedDarwinSource = sharedDarwinSource ?? false;
241269

242-
IOSPlugin.fromYaml(this.name, YamlMap yaml)
243-
: assert(validate(yaml)), // TODO(zanderso): https://github.com/flutter/flutter/issues/67241
244-
classPrefix = '',
245-
pluginClass = yaml[kPluginClass] as String?,
246-
dartPluginClass = yaml[kDartPluginClass] as String?,
247-
ffiPlugin = yaml[kFfiPlugin] as bool? ?? false,
248-
defaultPackage = yaml[kDefaultPackage] as String?,
249-
sharedDarwinSource = yaml[kSharedDarwinSource] as bool? ?? false;
270+
factory IOSPlugin.fromYaml(String name, YamlMap yaml) {
271+
assert(validate(yaml)); // TODO(zanderso): https://github.com/flutter/flutter/issues/67241
272+
273+
final String? dartPluginClass = yaml[kDartPluginClass] as String?;
274+
final String? dartFileName = yaml[kDartFileName] as String?;
275+
276+
if (dartPluginClass == null && dartFileName != null) {
277+
throwToolExit('"dartFileName" cannot be specified without "dartPluginClass" in iOS platform of plugin "$name"');
278+
}
279+
280+
return IOSPlugin(
281+
name: name,
282+
classPrefix: '',
283+
pluginClass: yaml[kPluginClass] as String?,
284+
dartPluginClass: dartPluginClass,
285+
dartFileName: dartFileName,
286+
ffiPlugin: yaml[kFfiPlugin] as bool? ?? false,
287+
defaultPackage: yaml[kDefaultPackage] as String?,
288+
sharedDarwinSource: yaml[kSharedDarwinSource] as bool? ?? false,
289+
);
290+
}
250291

251292
static bool validate(YamlMap yaml) {
252293
return yaml[kPluginClass] is String ||
@@ -265,6 +306,7 @@ class IOSPlugin extends PluginPlatform implements NativeOrDartPlugin, DarwinPlug
265306
final String classPrefix;
266307
final String? pluginClass;
267308
final String? dartPluginClass;
309+
final String? dartFileName;
268310
final bool ffiPlugin;
269311
final String? defaultPackage;
270312

@@ -289,6 +331,7 @@ class IOSPlugin extends PluginPlatform implements NativeOrDartPlugin, DarwinPlug
289331
'prefix': classPrefix,
290332
if (pluginClass != null) 'class': pluginClass,
291333
if (dartPluginClass != null) kDartPluginClass : dartPluginClass,
334+
if (dartFileName != null) kDartFileName : dartFileName,
292335
if (ffiPlugin) kFfiPlugin: true,
293336
if (sharedDarwinSource) kSharedDarwinSource: true,
294337
if (defaultPackage != null) kDefaultPackage : defaultPackage,
@@ -301,25 +344,43 @@ class IOSPlugin extends PluginPlatform implements NativeOrDartPlugin, DarwinPlug
301344
/// The [name] of the plugin is required. Either [dartPluginClass] or
302345
/// [pluginClass] or [ffiPlugin] are required.
303346
/// [pluginClass] will be the entry point to the plugin's native code.
347+
/// [dartFileName] is not required and will be used only if [dartPluginClass]
348+
/// provided.
304349
class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin, DarwinPlugin {
305350
const MacOSPlugin({
306351
required this.name,
307352
this.pluginClass,
308353
this.dartPluginClass,
354+
this.dartFileName,
309355
bool? ffiPlugin,
310356
this.defaultPackage,
311357
bool? sharedDarwinSource,
312358
}) : ffiPlugin = ffiPlugin ?? false,
313359
sharedDarwinSource = sharedDarwinSource ?? false;
314360

315-
MacOSPlugin.fromYaml(this.name, YamlMap yaml)
316-
: assert(validate(yaml)),
317-
// Treat 'none' as not present. See https://github.com/flutter/flutter/issues/57497.
318-
pluginClass = yaml[kPluginClass] == 'none' ? null : yaml[kPluginClass] as String?,
319-
dartPluginClass = yaml[kDartPluginClass] as String?,
320-
ffiPlugin = yaml[kFfiPlugin] as bool? ?? false,
321-
defaultPackage = yaml[kDefaultPackage] as String?,
322-
sharedDarwinSource = yaml[kSharedDarwinSource] as bool? ?? false;
361+
factory MacOSPlugin.fromYaml(String name, YamlMap yaml) {
362+
assert(validate(yaml));
363+
364+
final String? dartPluginClass = yaml[kDartPluginClass] as String?;
365+
final String? dartFileName = yaml[kDartFileName] as String?;
366+
367+
if (dartPluginClass == null && dartFileName != null) {
368+
throwToolExit('"dartFileName" cannot be specified without "dartPluginClass" in macOS platform of plugin "$name"');
369+
}
370+
371+
// Treat 'none' as not present. See https://github.com/flutter/flutter/issues/57497.
372+
final String? pluginClass = yaml[kPluginClass] == 'none' ? null : yaml[kPluginClass] as String?;
373+
374+
return MacOSPlugin(
375+
name: name,
376+
pluginClass: pluginClass,
377+
dartPluginClass: dartPluginClass,
378+
dartFileName: dartFileName,
379+
ffiPlugin: yaml[kFfiPlugin] as bool?,
380+
defaultPackage: yaml[kDefaultPackage] as String?,
381+
sharedDarwinSource: yaml[kSharedDarwinSource] as bool?,
382+
);
383+
}
323384

324385
static bool validate(YamlMap yaml) {
325386
return yaml[kPluginClass] is String ||
@@ -334,6 +395,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin, DarwinPl
334395
final String name;
335396
final String? pluginClass;
336397
final String? dartPluginClass;
398+
final String? dartFileName;
337399
final bool ffiPlugin;
338400
final String? defaultPackage;
339401

@@ -357,6 +419,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin, DarwinPl
357419
'name': name,
358420
if (pluginClass != null) 'class': pluginClass,
359421
if (dartPluginClass != null) kDartPluginClass: dartPluginClass,
422+
if (dartFileName != null) kDartFileName: dartFileName,
360423
if (ffiPlugin) kFfiPlugin: true,
361424
if (sharedDarwinSource) kSharedDarwinSource: true,
362425
if (defaultPackage != null) kDefaultPackage: defaultPackage,
@@ -368,12 +431,15 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin, DarwinPl
368431
///
369432
/// The [name] of the plugin is required. Either [dartPluginClass] or [pluginClass] are required.
370433
/// [pluginClass] will be the entry point to the plugin's native code.
434+
/// [dartFileName] is not required and will be used only if [dartPluginClass]
435+
/// provided.
371436
class WindowsPlugin extends PluginPlatform
372437
implements NativeOrDartPlugin, VariantPlatformPlugin {
373438
const WindowsPlugin({
374439
required this.name,
375440
this.pluginClass,
376441
this.dartPluginClass,
442+
this.dartFileName,
377443
bool? ffiPlugin,
378444
this.defaultPackage,
379445
this.variants = const <PluginPlatformVariant>{},
@@ -405,10 +471,18 @@ class WindowsPlugin extends PluginPlatform
405471
// future non-breaking.
406472
}
407473
}
474+
475+
final String? dartPluginClass = yaml[kDartPluginClass] as String?;
476+
final String? dartFileName = yaml[kDartFileName] as String?;
477+
478+
if (dartPluginClass == null && dartFileName != null) {
479+
throwToolExit('"dartFileName" cannot be specified without "dartPluginClass" in Windows platform of plugin "$name"');
480+
}
408481
return WindowsPlugin(
409482
name: name,
410483
pluginClass: pluginClass,
411-
dartPluginClass: yaml[kDartPluginClass] as String?,
484+
dartPluginClass: dartPluginClass,
485+
dartFileName: dartFileName,
412486
ffiPlugin: yaml[kFfiPlugin] as bool?,
413487
defaultPackage: yaml[kDefaultPackage] as String?,
414488
variants: variants,
@@ -427,6 +501,7 @@ class WindowsPlugin extends PluginPlatform
427501
final String name;
428502
final String? pluginClass;
429503
final String? dartPluginClass;
504+
final String? dartFileName;
430505
final bool ffiPlugin;
431506
final String? defaultPackage;
432507
final Set<PluginPlatformVariant> variants;
@@ -450,6 +525,7 @@ class WindowsPlugin extends PluginPlatform
450525
if (pluginClass != null) 'class': pluginClass,
451526
if (pluginClass != null) 'filename': _filenameForCppClass(pluginClass!),
452527
if (dartPluginClass != null) kDartPluginClass: dartPluginClass,
528+
if (dartFileName != null) kDartFileName: dartFileName,
453529
if (ffiPlugin) kFfiPlugin: true,
454530
if (defaultPackage != null) kDefaultPackage: defaultPackage,
455531
};
@@ -460,23 +536,39 @@ class WindowsPlugin extends PluginPlatform
460536
///
461537
/// The [name] of the plugin is required. Either [dartPluginClass] or [pluginClass] are required.
462538
/// [pluginClass] will be the entry point to the plugin's native code.
539+
/// [dartFileName] is not required and will be used only if [dartPluginClass]
540+
/// provided.
463541
class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
464542
const LinuxPlugin({
465543
required this.name,
466544
this.pluginClass,
467545
this.dartPluginClass,
546+
this.dartFileName,
468547
bool? ffiPlugin,
469548
this.defaultPackage,
470549
}) : ffiPlugin = ffiPlugin ?? false,
471550
assert(pluginClass != null || dartPluginClass != null || (ffiPlugin ?? false) || defaultPackage != null);
472551

473-
LinuxPlugin.fromYaml(this.name, YamlMap yaml)
474-
: assert(validate(yaml)),
475-
// Treat 'none' as not present. See https://github.com/flutter/flutter/issues/57497.
476-
pluginClass = yaml[kPluginClass] == 'none' ? null : yaml[kPluginClass] as String?,
477-
dartPluginClass = yaml[kDartPluginClass] as String?,
478-
ffiPlugin = yaml[kFfiPlugin] as bool? ?? false,
479-
defaultPackage = yaml[kDefaultPackage] as String?;
552+
factory LinuxPlugin.fromYaml(String name, YamlMap yaml) {
553+
assert(validate(yaml));
554+
555+
final String? dartPluginClass = yaml[kDartPluginClass] as String?;
556+
final String? dartFileName = yaml[kDartFileName] as String?;
557+
558+
if (dartPluginClass == null && dartFileName != null) {
559+
throwToolExit('"dartFileName" cannot be specified without "dartPluginClass" in Linux platform of plugin "$name"');
560+
}
561+
562+
return LinuxPlugin(
563+
name: name,
564+
// Treat 'none' as not present. See https://github.com/flutter/flutter/issues/57497.
565+
pluginClass: yaml[kPluginClass] == 'none' ? null : yaml[kPluginClass] as String?,
566+
dartPluginClass: dartPluginClass,
567+
dartFileName: dartFileName,
568+
ffiPlugin: yaml[kFfiPlugin] as bool? ?? false,
569+
defaultPackage: yaml[kDefaultPackage] as String?,
570+
);
571+
}
480572

481573
static bool validate(YamlMap yaml) {
482574
return yaml[kPluginClass] is String ||
@@ -490,6 +582,7 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
490582
final String name;
491583
final String? pluginClass;
492584
final String? dartPluginClass;
585+
final String? dartFileName;
493586
final bool ffiPlugin;
494587
final String? defaultPackage;
495588

@@ -509,6 +602,7 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
509602
if (pluginClass != null) 'class': pluginClass,
510603
if (pluginClass != null) 'filename': _filenameForCppClass(pluginClass!),
511604
if (dartPluginClass != null) kDartPluginClass: dartPluginClass,
605+
if (dartFileName != null) kDartFileName: dartFileName,
512606
if (ffiPlugin) kFfiPlugin: true,
513607
if (defaultPackage != null) kDefaultPackage: defaultPackage,
514608
};

0 commit comments

Comments
 (0)