Flutter Android v2 Embedding 下旧版(v1)插件的注册兼容与部分注册:从“自动反射注册”到手动控制(附 flutter 仓库源码解析)
Flutter Android v2 Embedding 下旧版(v1)插件的注册兼容与部分注册从“自动反射注册”到手动控制附 flutter 仓库源码解析【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter关联文档Experimental-Use-old-plugins-with-new-embedding.md归档 Wiki本文围绕 Flutter Android 引擎迁移到 v2 Embedding 后“插件如何被注册”这一核心问题展开先说明默认的“反射式全量自动注册”机制及其底层实现再完整演示如何关闭自动注册、实现部分插件注册partial plugin registration并说明 v1旧版插件在 v2 Embedding 下通过ShimPluginRegistry桥接使用的历史方案及其与当前仓库源码的对应关系。读完本文你将掌握FlutterEngine各构造参数对插件注册的实际影响、provideFlutterEngine()/configureFlutterEngine()的正确覆写姿势、缓存引擎与 Activity/Fragment 两种接入路径的差异以及为什么本文所述的代码示例在当前版本的 Android 嵌入层中需要改写为纯 v2 手动注册。1. 背景v2 Embedding 与“自动插件注册”从何而来从 v1 Embedding 迁移到 v2 Embedding 后Flutter 引入了一套基于FlutterEngine与FlutterPlugin接口的新插件体系其最大卖点之一是插件注册不再需要开发者手工编写注册代码。v2 的 Android Embedding 内置了一段基于反射的代码可以在运行时自动找到并注册你在pubspec.yaml中声明的所有插件。这段逻辑在源码中的位置非常明确GeneratedPluginRegister.javapublic static void registerGeneratedPlugins(NonNull FlutterEngine flutterEngine) { try { Class? generatedPluginRegistrant Class.forName(io.flutter.plugins.GeneratedPluginRegistrant); Method registrationMethod generatedPluginRegistrant.getDeclaredMethod(registerWith, FlutterEngine.class); registrationMethod.invoke(null, flutterEngine); } catch (Exception e) { Log.e(TAG, Tried to automatically register plugins with FlutterEngine ( flutterEngine ) but could not find or invoke the GeneratedPluginRegistrant.); } }该类的源码注释直接点明了这一设计的关键事实GeneratedPluginRegistrant并非引擎自带而是Flutter 工具链在构建期根据pubspec.yaml中的插件依赖生成到应用工程中的一个类因此引擎无法在编译期依赖它只能运行时用反射查找。生成出的注册代码本质上只是遍历pubspec.yaml中每个插件对其调用FlutterPlugin#onAttachedToEngine(FlutterPluginBinding)。如果反射找不到或无法调用该生成类注册会“静默失败”fizzle此时应用仍可自己写代码显式注册插件。注释同时给出了两条“关闭自动注册”的官方途径详见第 2、3 节。这也是关联文档开头那句话“v2 Android embedding includes reflection code that should find and register all plugins listed in yourpubspec.yamlwithout any intervention”的源码级佐证。自动注册的两个“开关”是且的关系值得注意的是自动注册并不是只看一个开关。在 FlutterEngine.java 的构造器末尾实际的调用条件是这样的约 L425-L429// Only automatically register plugins if both constructor parameter and // loaded AndroidManifest config turn this feature on. if (automaticallyRegisterPlugins flutterLoader.automaticallyRegisterPlugins()) { GeneratedPluginRegister.registerGeneratedPlugins(this); }也就是说只有当“构造器入参automaticallyRegisterPlugins true”与“FlutterLoader.automaticallyRegisterPlugins()来自应用清单配置见 FlutterLoader.java L818-L820同时为真时才会触发反射式全量注册。这为“按需注册”提供了两个可独立操作的切入点。2. 部分注册第一步构建一个“不自动注册插件”的 FlutterEngine关联文档的核心使用场景是部分插件注册partial plugin registration不让 Flutter 注册pubspec.yaml里的全部插件而是只注册你挑选出来的那部分。第一步永远是——构造一个关闭了自动注册的FlutterEngine。有两种取巧的构造路径路径 A使用缓存的FlutterEngineFlutterEngineCache见 FlutterEngineCache.java路径 B在FlutterActivity或FlutterFragment中覆写provideFlutterEngine()由你自己返回一个不做自动注册的引擎实例。关联文档给出的构造代码对应引擎源码中“可传FlutterLoader/FlutterJNI/dartVmArgs/开关”的那个全参数构造即 FlutterEngine.java L270-L283 的FlutterEngine(Context, FlutterLoader, FlutterJNI, String[], boolean)FlutterEngine flutterEngine new FlutterEngine( context, FlutterLoader.getInstance(), new FlutterJNI(), dartVmArgs, // 不需要 VM 参数时可传空数组 false // 关键开关告诉 FlutterEngine 不要自动注册插件 );其中最后一个boolean参数在引擎 javadoc 中的解释是如果为 true插件会在“该构造器执行期间”即被注册If plugins are automatically registered, then they are registered during the execution of this constructor。因此把这一位设为false你就能拿到一个“插件列表为空、完全由你掌控”的引擎。更简洁的现代等价写法需要说明的是上述 5 参写法属于“高度可定制”的重载。对于绝大多数“只是不想自动注册”的场景本仓库的嵌入层还提供了更简洁的重载FlutterEngine.java L205-L215不必手动传入FlutterLoader与FlutterJNI// FlutterEngine(Context, String[] dartVmArgs, boolean automaticallyRegisterPlugins) FlutterEngine flutterEngine new FlutterEngine(context, dartVmArgs, false);3. 部分注册第二步把想要保留的插件注册进去3.1 走FlutterActivity/FlutterFragment覆写路径如果你是在FlutterActivity或FlutterFragment中通过覆写provideFlutterEngine()提供引擎的那么注册插件的正确落点是同时覆写configureFlutterEngine()。框架会在引擎与宿主Activity生命周期挂钩、插件可获得Activity上下文之后回调该方法因此这里注册的插件才能安全地使用 Activity 级能力。public void configureFlutterEngine(FlutterEngine engine) { // ShimPluginRegistry 是 v2 Embedding 与 v1 插件协作的方式 ShimPluginRegistry shimPluginRegistry new ShimPluginRegistry( flutterEngine, new PlatformViewsController() ); // 需要的话把 v1 插件加入 shim // MyV1Plugin.registerWith( // shimPluginRegistry.registrarFor(com.my.package.MyV1Plugin) // ); // 把你想要的 v2 插件逐个加入 // engine.getPlugins().add(new MyPlugin()); }从框架实现看configureFlutterEngine()并不只存在于这两个类里。它是接口 FlutterEngineConfigurator.java 的唯一方法而FlutterActivity、FlutterFragment在内部都由 FlutterActivityAndFragmentDelegate.java 统一驱动。该 Delegate 的onAttach()会依序调用宿主的provideFlutterEngine()拿到引擎与configureFlutterEngine(flutterEngine)此时引擎已可用、Activity 已附着源码见 FlutterActivityAndFragmentDelegate.java L228 附近。这解释了为什么“引擎构造”和“插件注册”被刻意拆成两个回调——你可以在provideFlutterEngine()里给出不带插件的引擎再在configureFlutterEngine()里精准补入插件。注意不要在configureFlutterEngine()中调用super.configureFlutterEngine(engine)否则默认实现会再次触发GeneratedPluginRegistrant的全量注册使“部分注册”失效。3.2 走缓存FlutterEngine路径如果你选用的是缓存引擎方案而非覆写FlutterActivity/FlutterFragment方法那么注册时机就非常自由——甚至可以在FlutterEngine构造完成后立刻注册// 实例化缓存 FlutterEngine FlutterEngine flutterEngine new FlutterEngine( context, FlutterLoader.getInstance(), new FlutterJNI(), dartVmArgs, // 不需要 VM 参数时传空数组 false // 关闭自动注册 ); // 立刻向缓存引擎加入插件 ShimPluginRegistry shimPluginRegistry new ShimPluginRegistry( flutterEngine, new PlatformViewsController() ); // 把 v1 插件加入 shim // MyV1Plugin.registerWith( // shimPluginRegistry.registrarFor(com.my.package.MyV1Plugin) // ); // 加入想要的 v2 插件 // engine.getPlugins().add(new MyPlugin());但关联文档在这里给出了一条非常重要的时序警告部分 v1 插件在注册那一刻就期望一个可用的Activity。如果你在“引擎刚构造完”的时机注册此时引擎尚未绑定任何 Activity这类插件将拿不到 Activity从而出错。因此凡是“需要在注册时访问 Activity”的插件应放在configureFlutterEngine()里注册此时 Activity 已可用只有那些不依赖 Activity 的插件才适合在引擎构造完成后立刻注册。3.3getPlugins().add(...)的本质v2 插件的手动注册口上面两段示例末尾出现的engine.getPlugins().add(new MyPlugin())在当前仓库的嵌入层中仍然有效它对应FlutterEngine内部的FlutterEngineConnectionRegistryFlutterEngineConnectionRegistry.java实现了 PluginRegistry.java 中add(FlutterPlugin)的能力。新插件只需要实现 FlutterPlugin.java在onAttachedToEngine()中建立 MethodChannel / EventChannel 等监听即可。若想要自定义“何时注册哪个插件”直接复制GeneratedPluginRegistrant生成内容、逐个getPlugins().add(...)正是GeneratedPluginRegister源码注释给出的官方建议。4. 重要前提ShimPluginRegistry在当前仓库中已不存在历史方案说明本文关联文档属于仓库docs/wiki_archive/下的归档 Wiki记录的是 v1→v2 Embedding 迁移过渡期的“实验性”做法。因此文档中的两段示例都出现了ShimPluginRegistry与 v1 插件的registerWith(...)静态方法——这是当年让旧插件在新引擎里继续工作的桥接层。但从当前仓库的 Android 嵌入层源码结构看在engine/src/flutter/shell/platform/android/io/flutter/全目录范围内已经搜索不到ShimPluginRegistry类的定义也搜索不到 v1 插件体系使用的registrarFor(...)/registerWith(...)唯一的registerWith命中是GeneratedPluginRegister通过反射调用的字符串方法名。也就是说本文第 3 节给出的两段含ShimPluginRegistry的示例面向的是当年引入 v1 桥接的过渡版本在当前这份仓库快照中旧版 v1 插件注册桥已被移除示例代码直接照搬是无法通过编译的但这不影响本文所讲机制的有效性automaticallyRegisterPlugins构造参数、provideFlutterEngine()configureFlutterEngine()的生命周期钩子、以及getPlugins().add(...)手动注册都是当前嵌入层仍然在用的“活代码”见第 2、3 节引用的源码位置。如果你在当前版本上想要“只注册部分插件”等价的可编译写法是纯 v2 形式public class MyFlutterActivity extends FlutterActivity { Override public void configureFlutterEngine(NonNull FlutterEngine flutterEngine) { // 不调用 super.configureFlutterEngine(...)从而跳过 GeneratedPluginRegistrant 全量注册 flutterEngine.getPlugins().add(new MyPlugin()); // 继续添加其它精选插件... } }搭配第 2 节中关闭自动注册的引擎构造即可实现与归档文档目标一致的“部分插件注册”。5. 实践对照表文档方案 × 当前源码归档文档中的做法当前仓库中的对应实现状态反射自动注册所有pubspec.yaml插件GeneratedPluginRegister.java 反射调用构建期生成的io.flutter.plugins.GeneratedPluginRegistrant保留构造器入参false关闭自动注册FlutterEngine各重载构造的automaticallyRegisterPlugins位FlutterEngine.java L270-L283、L205-L215且需与 manifest 级开关同时为真L427-L429保留覆写provideFlutterEngine()FlutterActivity/FlutterFragment提供自定义引擎保留覆写configureFlutterEngine()注册插件FlutterEngineConfigurator接口由 FlutterActivityAndFragmentDelegate.java 统一调度约 L228保留engine.getPlugins().add(...)注册 v2 插件PluginRegistry.add(FlutterPlugin)经由FlutterEngineConnectionRegistry实现保留ShimPluginRegistry桥接 v1 插件在当前仓库 Android 嵌入层源码中已不存在已移除仅存在于归档文档缓存引擎路径FlutterEngineCache.java保留6. 总结与建议默认无需干预v2 Embedding 会通过反射自动注册pubspec.yaml中的所有插件若你期望的插件未被自动注册先按官方建议提交 issue而不是盲目上手写注册代码。何时需要“部分注册”当你希望精细控制插件初始化时机、插件列表或减少启动期不必要的注册工作GeneratedPluginRegister源码注释亦提到“延迟/禁用自动注册可用于微调启动时延特征”时关闭自动注册并按需注册。两条关闭路径二选一要么构造引擎时把automaticallyRegisterPlugins设为false要么覆写configureFlutterEngine()且不调用super。留意 Activity 依赖凡是注册瞬间需要 Activity 的插件请务必在configureFlutterEngine()中注册缓存引擎上“构造完立刻注册”只适用于不依赖 Activity 的插件。以当前源码为准归档文档中的ShimPluginRegistry/v1registerWith代码属于过渡期产物当前仓库已无对应实现需要新旧知识对接的读者应以本文第 4 节的“现状说明”和源码路径为准进行取舍。【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考