问题背景与分析
在大型应用开发中,多团队并行开发不同业务模块时,模块间的路由跳转会导致严重的耦合问题。以案例中的A.har、B.har和C.har三个模块为例:
- 循环依赖问题:模块间的相互跳转形成环形调用链路
- 开发态耦合:需要显式import其他模块的组件
- 编译依赖:模块无法独立编译,影响开发效率
现有方案的问题
当前基于Navigation的基本实现方案存在以下缺陷:
- 强耦合的import方式:必须显式导入所有目标页面组件
- 集中式路由配置:所有路由集中在使用方模块配置
- 编译依赖:模块间存在直接依赖关系,无法独立编译
解耦方案设计
架构设计
采用"RouterModule + EntryHap + 业务模块"的三层架构:
-
RouterModule:
- 独立的路由管理HAR包
- 提供路由注册、跳转和动态加载能力
- 维护全局路由表和路由栈
-
EntryHap:
- 应用主入口模块
- 唯一直接依赖所有业务模块
- 初始化Navigation并关联路由栈
-
业务模块(A.har/B.har):
- 仅依赖RouterModule
- 初始化时注册自身路由
- 不直接依赖其他业务模块
依赖关系
EntryHap → A.har
→ B.har
→ RouterModule.har
A.har → RouterModule.har
B.har → RouterModule.har
关键技术实现
1. 路由管理模块(RouterModule)
export class RouterModule {
// 路由表:存储所有注册的路由组件
static builderMap: Map<string, WrappedBuilder<[object]>> = new Map();
// 路由栈表:支持多Navigation场景
static routerMap: Map<string, NavPathStack> = new Map();
// 路由注册
public static registerBuilder(builderName: string, builder: WrappedBuilder<[object]>): void {
this.builderMap.set(builderName, builder);
}
// 路由跳转
public static async push(router: RouterModel): Promise<void> {
const harName = router.builderName.split('_')[0];
await import(harName).then((ns: ESObject) => ns.harInit(router.builderName));
this.getRouter(router.routerName).pushPath({
name: router.builderName,
param: router.param
});
}
}
2. 主入口模块(EntryHap)
@Entry
@***ponent
struct EntryHap {
@State entryHapRouter: NavPathStack = new NavPathStack();
aboutToAppear() {
RouterModule.createRouter(RouterNameConstants.ENTRY_HAP, this.entryHapRouter);
};
@Builder
routerMap(builderName: string, param: object) {
RouterModule.getBuilder(builderName).builder(param);
};
build() {
Navigation(this.entryHapRouter) {
// 首页内容...
}
.navDestination(this.routerMap);
}
}
3. 业务模块实现(B.har示例)
路由注册:
// B1页面
@Builder
export function harBuilder(value: object) {
NavDestination() {
// 页面内容...
}
}
// 模块初始化时注册路由
const builderName = "B_B1";
if (!RouterModule.getBuilder(builderName)) {
let builder: WrappedBuilder<[object]> = wrapBuilder(harBuilder);
RouterModule.registerBuilder(builderName, builder);
}
动态加载优化:
// harB的index.ets
export function harInit(builderName: string): void {
switch (builderName) {
case "B_B1": import("./B1"); break;
case "B_B2": import("./B2"); break;
case "B_B3": import("./B3"); break;
}
}
方案优势
-
完全解耦:
- 业务模块间无直接依赖
- 通过RouterModule进行间接通信
-
动态加载:
- 按需加载目标模块
- 减少启动初始化负担
-
多路由栈支持:
- 可管理多个Navigation的路由栈
- 适应复杂业务场景
-
独立编译:
- 各模块可独立开发编译
- 提高团队协作效率
实施建议
-
命名规范:
- 制定统一的路由命名规则(如"模块名_页面名")
- 使用常量管理路由名称
-
类型安全:
- 为RouterModel等核心类提供类型定义
- 添加必要的类型检查
-
错误处理:
- 增强路由跳转的错误处理
- 提供降级方案(如跳转失败显示默认页)
-
性能监控:
- 跟踪动态加载耗时
- 优化高频使用页面的预加载策略
此方案通过中间层路由管理和动态加载机制,有效解决了大型应用中多模块开发的耦合问题,为复杂业务场景下的模块化开发提供了可扩展的架构基础。