FoxTalk
文档/增强模块

增强模块

FoxTalk 把所有扩展能力做成模块, base 工程编译不依赖任何模块代码。模块通过 FeatureRegistry 注册 route / 消息类型 / 组件构造器, base 工程通过 featureById 反射拿。删模块 = 删 lib/src/<module>/ + 注释 app_modules.dart 一行, 主流程不受影响。

lib/src/modules/feature_module.dart 定义 FeatureModule 接口, 每个模块实现一个同名 class, 在 register 方法里把自己的能力注册到 registry。

abstract interface class FeatureModule {
  String get id;
  void register(FeatureRegistry registry);
}

FeatureRegistry 暴露多种 register 方法 (registerRoute / registerComposerPanelItem / registerMessageContentHandler / registerLifecycle / registerCmdHandler 等), 每条注册带 id + moduleId + value, base 工程通过 featureById(id) 取出 value。

Endpoint pattern: 反射拿实现

Base 工程不直接 import 模块代码, 而是定义接口 (例 ThirdPartyLoginContract) + 在 ModuleFeatureIds 集中声明 id 常量。模块端实现接口后通过 registerFeature 写入 registry, base 端通过 featureById 拿到 value 后强转用:

// 模块端
registry.registerFeature(
  id: ModuleFeatureIds.thirdPartyLoginService,
  moduleId: id,
  value: ThirdPartyLoginServiceImpl(),
);

// base 工程
final feature = registry.featureById(
  ModuleFeatureIds.thirdPartyLoginService,
);
final service = feature?.value as ThirdPartyLoginContract?;
// 拿不到 = 模块未注册, UI 隐藏对应入口

好处: 删模块时 base 工程编译完全不受影响。featureById 返 null 触发 UI 兜底逻辑 (按钮不渲染 / 入口隐藏), 跟 iOS 原版 Podfile 注释一行删 module 同款体验。

加新模块的 5 步

  • 在 lib/src/modules/module_ids.dart 的 ExtensionModuleIds + ModuleFeatureIds (如需暴露 feature 给 base) 加 ID 常量。
  • 新建 lib/src/<module>/<module>_module.dart, 实现 FeatureModule, 在 register 里调 registry.includeModule + 各类 registerXxx。
  • 新建 lib/src/<module>/ 下其他源码 (页面 / service / API), 模块内部代码自由组织。
  • 在 lib/src/modules/app_modules.dart 顶部 import 模块文件, 在 registerModules 函数体追加一行 const XxxModule().register(registry)。
  • 跑 flutter analyze + 真机装机自测, 验证 UI 入口出现且不影响其他模块。
last updated · 2026-06