diff --git a/packages/flutter_tools/lib/src/flutter_plugins.dart b/packages/flutter_tools/lib/src/flutter_plugins.dart index ec9196d002..d099e2630d 100644 --- a/packages/flutter_tools/lib/src/flutter_plugins.dart +++ b/packages/flutter_tools/lib/src/flutter_plugins.dart @@ -685,6 +685,9 @@ const String _dartPluginRegistryForNonWebTemplate = ''' // @dart = {{dartLanguageVersion}} +// When `{{mainEntrypoint}}` defines `main`, that definition is shadowed by the definition below. +export '{{mainEntrypoint}}'; + import '{{mainEntrypoint}}' as entrypoint; import 'dart:io'; // flutter_ignore: dart_io_import. {{#android}} diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/dart_plugin_registrant_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/dart_plugin_registrant_test.dart index 9a1a018656..64c628ded7 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/dart_plugin_registrant_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/dart_plugin_registrant_test.dart @@ -243,6 +243,9 @@ void main() { '\n' '// @dart = 2.12\n' '\n' + '// When `package:path_provider_example/main.dart` defines `main`, that definition is shadowed by the definition below.\n' + "export 'package:path_provider_example/main.dart';\n" + '\n' "import 'package:path_provider_example/main.dart' as entrypoint;\n" "import 'dart:io'; // flutter_ignore: dart_io_import.\n" "import 'package:path_provider_linux/path_provider_linux.dart';\n" @@ -382,6 +385,9 @@ void main() { '\n' '// @dart = 2.12\n' '\n' + '// When `file:///root/external.dart` defines `main`, that definition is shadowed by the definition below.\n' + "export 'file:///root/external.dart';\n" + '\n' "import 'file:///root/external.dart' as entrypoint;\n" "import 'dart:io'; // flutter_ignore: dart_io_import.\n" "import 'package:path_provider_linux/path_provider_linux.dart';\n" diff --git a/packages/flutter_tools/test/general.shard/dart_plugin_test.dart b/packages/flutter_tools/test/general.shard/dart_plugin_test.dart index 1774b53ce0..7485a606fe 100644 --- a/packages/flutter_tools/test/general.shard/dart_plugin_test.dart +++ b/packages/flutter_tools/test/general.shard/dart_plugin_test.dart @@ -599,6 +599,9 @@ void main() { '\n' '// @dart = 2.8\n' '\n' + '// When `package:app/main.dart` defines `main`, that definition is shadowed by the definition below.\n' + "export 'package:app/main.dart';\n" + '\n' "import 'package:app/main.dart' as entrypoint;\n" "import 'dart:io'; // flutter_ignore: dart_io_import.\n" "import 'package:url_launcher_android/url_launcher_android.dart';\n" @@ -699,6 +702,203 @@ void main() { ProcessManager: () => FakeProcessManager.any(), }); + testUsingContext('Rewires entrypoints', () async { + flutterProject.isModule = true; + + createFakeDartPlugins( + flutterProject, + flutterManifest, + fs, + { + 'url_launcher_android': ''' + flutter: + plugin: + implements: url_launcher + platforms: + android: + dartPluginClass: AndroidPlugin +''', + 'url_launcher_ios': ''' + flutter: + plugin: + implements: url_launcher + platforms: + ios: + dartPluginClass: IosPlugin +''', + 'url_launcher_macos': ''' + flutter: + plugin: + implements: url_launcher + platforms: + macos: + dartPluginClass: MacOSPlugin +''', + 'url_launcher_linux': ''' + flutter: + plugin: + implements: url_launcher + platforms: + linux: + dartPluginClass: LinuxPlugin +''', + 'url_launcher_windows': ''' + flutter: + plugin: + implements: url_launcher + platforms: + windows: + dartPluginClass: WindowsPlugin +''', + 'awesome_macos': ''' + flutter: + plugin: + implements: awesome + platforms: + macos: + dartPluginClass: AwesomeMacOS +''' + }); + + final Directory libDir = flutterProject.directory.childDirectory('lib'); + libDir.createSync(recursive: true); + + final File mainFile = libDir.childFile('main.dart'); + mainFile.writeAsStringSync(''' +// @dart = 2.8 +void main() { +} + +@pragma('vm:entry-point') +void dream() => run(interactive: false); + +@pragma('vm:entry-point', foobar) +void dreamWithFlags() => run(interactive: false); +'''); + final PackageConfig packageConfig = await loadPackageConfigWithLogging( + flutterProject.directory.childDirectory('.dart_tool').childFile('package_config.json'), + logger: globals.logger, + throwOnError: false, + ); + await generateMainDartWithPluginRegistrant( + flutterProject, + packageConfig, + 'package:app/main.dart', + mainFile, + throwOnPluginPubspecError: true, + ); + expect(flutterProject.dartPluginRegistrant.readAsStringSync(), + '//\n' + '// Generated file. Do not edit.\n' + '// This file is generated from template in file `flutter_tools/lib/src/flutter_plugins.dart`.\n' + '//\n' + '\n' + '// @dart = 2.8\n' + '\n' + '// When `package:app/main.dart` defines `main`, that definition is shadowed by the definition below.\n' + "export 'package:app/main.dart';\n" + '\n' + "import 'package:app/main.dart' as entrypoint;\n" + "import 'dart:io'; // flutter_ignore: dart_io_import.\n" + "import 'package:url_launcher_android/url_launcher_android.dart';\n" + "import 'package:url_launcher_ios/url_launcher_ios.dart';\n" + "import 'package:url_launcher_linux/url_launcher_linux.dart';\n" + "import 'package:awesome_macos/awesome_macos.dart';\n" + "import 'package:url_launcher_macos/url_launcher_macos.dart';\n" + "import 'package:url_launcher_windows/url_launcher_windows.dart';\n" + '\n' + "@pragma('vm:entry-point')\n" + 'class _PluginRegistrant {\n' + '\n' + " @pragma('vm:entry-point')\n" + ' static void register() {\n' + ' if (Platform.isAndroid) {\n' + ' try {\n' + ' AndroidPlugin.registerWith();\n' + ' } catch (err) {\n' + ' print(\n' + " '`url_launcher_android` threw an error: \$err. '\n" + " 'The app may not function as expected until you remove this plugin from pubspec.yaml'\n" + ' );\n' + ' rethrow;\n' + ' }\n' + '\n' + ' } else if (Platform.isIOS) {\n' + ' try {\n' + ' IosPlugin.registerWith();\n' + ' } catch (err) {\n' + ' print(\n' + " '`url_launcher_ios` threw an error: \$err. '\n" + " 'The app may not function as expected until you remove this plugin from pubspec.yaml'\n" + ' );\n' + ' rethrow;\n' + ' }\n' + '\n' + ' } else if (Platform.isLinux) {\n' + ' try {\n' + ' LinuxPlugin.registerWith();\n' + ' } catch (err) {\n' + ' print(\n' + " '`url_launcher_linux` threw an error: \$err. '\n" + " 'The app may not function as expected until you remove this plugin from pubspec.yaml'\n" + ' );\n' + ' rethrow;\n' + ' }\n' + '\n' + ' } else if (Platform.isMacOS) {\n' + ' try {\n' + ' AwesomeMacOS.registerWith();\n' + ' } catch (err) {\n' + ' print(\n' + " '`awesome_macos` threw an error: \$err. '\n" + " 'The app may not function as expected until you remove this plugin from pubspec.yaml'\n" + ' );\n' + ' rethrow;\n' + ' }\n' + '\n' + ' try {\n' + ' MacOSPlugin.registerWith();\n' + ' } catch (err) {\n' + ' print(\n' + " '`url_launcher_macos` threw an error: \$err. '\n" + " 'The app may not function as expected until you remove this plugin from pubspec.yaml'\n" + ' );\n' + ' rethrow;\n' + ' }\n' + '\n' + ' } else if (Platform.isWindows) {\n' + ' try {\n' + ' WindowsPlugin.registerWith();\n' + ' } catch (err) {\n' + ' print(\n' + " '`url_launcher_windows` threw an error: \$err. '\n" + " 'The app may not function as expected until you remove this plugin from pubspec.yaml'\n" + ' );\n' + ' rethrow;\n' + ' }\n' + '\n' + ' }\n' + ' }\n' + '\n' + '}\n' + '\n' + 'typedef _UnaryFunction = dynamic Function(List args);\n' + 'typedef _NullaryFunction = dynamic Function();\n' + '\n' + 'void main(List args) {\n' + ' if (entrypoint.main is _UnaryFunction) {\n' + ' (entrypoint.main as _UnaryFunction)(args);\n' + ' } else {\n' + ' (entrypoint.main as _NullaryFunction)();\n' + ' }\n' + '}\n' + , + ); + }, overrides: { + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + }); + testUsingContext('Plugin without platform support throws tool exit', () async { flutterProject.isModule = false;