Repository navigation
Implement dartPluginClass support for plugins #52267
Description
The federated plugin design describes having a dartPluginClass for each platform, allowing the registration of Dart plugin implementation details on a per-platform basis. Currently actually doing that is only possible on Web (AFAICT).
This is currently blocking implementation of path_provider and shared_preferences on Linux, where there's no need to use anything but pure Dart, because there's no way to bind the implementation to the interface package. (This is would also be very useful in conjunction with FFI; e.g., the Windows path_provider implementation could easily be Dart + FFI to a couple of system calls, significantly reducing the amount of code involved.)
Greg and I looked at this a little bit at the end of last week. Adding the auto-generation of a Dart registrant is simple, but we got stuck on actually injecting the call to that registrant in a way that doesn't break existing functionality (in particular, passing an arbitrary start point to the embedder API). I'm not sure if there was already a plan/design in place to address that.
/cc @amirh
Activity
stuartmorgan-g commentedon Mar 9, 2020
/cc @gspencergoog as well.
(I've added the desktop platform labels because I know we'll want it there, but presumably we'll want this on iOS and Android too).
amirh commentedon Mar 9, 2020
I was discussing this with @jonahwilliams awhile ago, one alternative we were considering was to generate a main function that wraps the app's main (and also invokes plugin activation), and use the generated main as the entry point.
Also note that there's some more discussion on how to bake this codegen in the tool in this follow-up doc.
One thing I'd like to bring up for consideration again (tomorrow's meeting is a good chance) is whether to trade ease of use of unendorsed plugins with infra simplicity (by making it the app-facing package's responsibility to activate endorsed implementations).
stuartmorgan-g commentedon Mar 9, 2020
How? I considered that, but couldn't see how that would work in practice. Taking macOS as a concrete example, if my native code passes any non-default entryPoint when starting the engine how would we wrap it? The generated Dart wrapper needs to know what entry point to call into, but the tooling doesn't know what the native code is going to pass.
amirh commentedon Mar 10, 2020
I didn't realize we let embeddings set the entry point. 🤔
@jonahwilliams are we doing something like that for web? do we allow a custom entry point there?
I guess if we want to keep going up this mountain we may propose VM support for an additional entry point. Though I'd really love a simpler solution.
[Just brainstorming] I'm not familiar with the VM bindings, do you know if it's possible for the engine to initiate invocation of a Dart method after runnning the initial entry point? (if that is possible I can imagine us adding code in widgets binding initialization to wait for the engine to indicate that plugins have been activated, and the engine will indicate that after invoking the generated registrant)
jonahwilliams commentedon Mar 10, 2020
No, the web doesn't really have an embedding so its not configurable.
stuartmorgan-g commentedon Mar 10, 2020
@chinmaygarde and/or @jason-simmons Do you know offhand the answer to the question above about whether we are able to invoke arbitrary Dart code from the embedding? I.e., could the native embedding code start up the engine, then immediately call some known function?
[path_provider] linux endorsement (#2789)
stuartmorgan-g commentedon Jun 4, 2020
Capturing from various discussions, the short-term solution to this problem is to directly register the dart-only implementation from the front-end package (example).
This has the downside that it requires an override option for registering a different implementation, meaning that for instance tests that want to use a mock must explicitly disable the platform registration (example).
62 remaining items
stuartmorgan-g commentedon Apr 23, 2021
Leaving open for mobile.
Implemented workaround for flutter/flutter#52267
xster commentedon Sep 16, 2021
Since there weren't much additional discussions after the register plugin entrypoint wrapping the real entrypoint proposal, I'm assuming that's rough direction? Is there a doc with more details on the proposal?
It's not too clear to me who calls that entrypoint. The embedding has ways of specifying an entrypoint when running the engine so it's a runtime problem rather than a compile time problem. How do we, at that point, switch out the real entrypoint the user called and wrap this plugin registration call around it?
stuartmorgan-g commentedon Sep 17, 2021
@blasten Is there a doc for what you implemented?
I wasn't involved in the reviews; I assumed that problem had been resolved since it was explicitly discussed several times above. As I've tried to extend it to mobile though, and found that it breaks
flutter test, it seems to me like that may not actually be the case.blasten commentedon Sep 17, 2021
There's no doc about the implementation by itself, but I can summarize it:
The engine (C++) calls the Dart plugin registrant: https://github.com/flutter/flutter/pull/87991/files#diff-68361f6fc9aafa5fa7de042eec4603dd4f321eb783a00edd57780ef78c1094bbR709. The only requirement is to define a top-level
_PluginRegistrantclass with a static methodregister(). Each should have@pragma('vm:entry-point').Wrapping
main.dartwas required because the Dart compiler had no other way to import a generated file from an arbitrary package that isn't imported by the app's dependency tree.flutter testshould work fine. @stuartmorgan please file an issue with repro steps if that isn't the case.flutter testshould set the set dart entrypoint anyways.I'm aware that the Android embedding allows to use an arbitrary entrypoint string. I think this is supported, although not tested. Since the engine only expects
_PluginRegistrant; it doesn't really matter if it's defined in main.dart or foo.dart, it only matters that it's defined. @xsterstuartmorgan-g commentedon Sep 17, 2021
It doesn't, as I said here: #87991 (comment). See also #88632 and #88794
blasten commentedon Sep 17, 2021
I see, sorry.
The fix seems to be to regenerate the generated entrypoint here using generateMainDartWithPluginRegistrant.
I thought
flutter testused the build system used elsewhere, but it doesn't seem like.stuartmorgan-g commentedon Sep 17, 2021
Thanks, I'll take a look at that. I hadn't had time yet to try to trace through everything to figure out where
flutter testbuilds were happening.The part that I'm still confused about though is: why is
flutter testcapable of overriding the original main, but not of overriding the wrapper main ingenerated_main.dart? Shouldn't that work the same way it used to? (And what is that way?)stuartmorgan-g commentedon Sep 17, 2021
That does appear to work, but I'd like to make sure I understand
a) why we need it, and
b) if we should be generating
generated_main.dartsomewhere else, because having it be a persistent file that points to a temp file that doesn't outlive theflutter testrun seems very questionable.blasten commentedon Sep 17, 2021
Discussed offline. The fix is #90288
github-actions commentedon Oct 16, 2021
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.