HarmonyOS《柚兔学伴》项目实战02-多模块架构设计与 HSP/HAR 模块化

HarmonyOS《柚兔学伴》项目实战02-多模块架构设计与 HSP/HAR 模块化 多模块架构设计与 HSP/HAR 模块化在 HarmonyOS 应用开发中随着业务复杂度的增长单模块工程往往难以满足代码组织、团队协作和构建效率的需求。柚兔学伴项目采用了多模块架构将不同业务和基础设施拆分为独立模块实现了清晰的职责划分与灵活的依赖管理。本文将深入剖析 HarmonyOS 的模块体系以及柚兔学伴的模块化实践。一、HarmonyOS 模块类型HarmonyOS 提供了三种模块类型适用于不同场景类型全称编译方式运行时共享适用场景Entry入口模块独立编译为 HAP仅自身使用应用主模块包含 UIAbilityHSPHarmony Shared Package动态共享包运行时单实例共享多模块共享代码减小包体积HARHarmony Archive静态共享包编译时拷贝到各模块三方库、简单共享逻辑HSP 与 HAR 的核心区别HSP动态共享包在应用运行时只加载一份实例多个模块引用同一 HSP 时共享同一份代码和资源因此可以有效减小应用安装包体积。但 HSP 不支持独立发布只能随应用一起打包。HAR静态共享包在编译时会被完整拷贝到每个依赖它的模块中。如果多个模块引用同一个 HAR每个模块都会包含一份副本包体积会增大。HAR 的优势在于支持独立发布到三方库市场且编译隔离性更好。选择原则内部共享模块优先用 HSP三方库或简单工具用 HAR。二、柚兔学伴的模块拆分柚兔学伴将项目拆为以下模块StudyPartner/ ├── entry/ # 入口模块HAP ├── common/ # 基础共享模块HAR ├── network/ # 网络请求层HAR ├── feature/ │ ├── todo/ # 待办/学习任务模块HAR │ ├── stroke/ # 笔画/书写模块HAR │ ├── chat/ # AI 对话模块HAR │ └── my/ # 个人中心模块HAR ├── cloud_objects/ # 云对象模块HAR └── smartxplayer/ # 播放器模块HAR模块职责划分common全局基础能力包括通用常量、日志工具、窗口工具、断点系统、路由管理、数据库、通用 UI 组件TopBar、LoadingView、IconText、TimerComponent等networkHTTP 请求封装包含 HttpManager、ApiHttpManager、URL 常量、响应模型feature/todo学习任务管理诗词、课本、PDF 阅读feature/stroke笔画书写练习feature/chatAI 智能对话feature/my个人中心、积分、设置、关于三、oh-package.json5 依赖配置模块间的依赖关系通过每个模块的oh-package.json5声明。本地模块引用使用file:协议指向相对路径。entry 模块的依赖entry 作为入口依赖所有业务模块// entry/oh-package.json5 { name: entry, version: 1.0.0, dependencies: { common: file:../common, stroke: file:../feature/stroke, todo: file:../feature/todo, my: file:../feature/my, chat: file:../feature/chat, cloud_objects: file:../cloud_objects } }feature 模块的依赖业务模块依赖 common 和 network// feature/chat/oh-package.json5 { name: chat, version: 1.0.0, main: Index.ets, dependencies: { common: file:../../common, network: file:../../network } }// feature/todo/oh-package.json5 { name: todo, version: 1.0.0, main: Index.ets, dependencies: { common: file:../../common, network: file:../../network, qtfm/smartxplayer: file:../../smartxplayer } }network 模块的依赖network 只依赖 common// network/oh-package.json5 { name: network, version: 1.0.0, main: Index.ets, dependencies: { common: file:../common } }依赖方向规则entry → feature → network → common形成单向依赖链避免循环依赖。四、Index.ets 统一导出设计每个模块通过根目录的Index.ets文件统一导出对外 API其他模块只需引用模块名即可使用。common/Index.etscommon 作为基础层导出量最大// common/Index.etsexport{CommonConstants,Role}from./src/main/ets/constant/CommonConstants;export{AgentConstant}from./src/main/ets/constant/AgentConstant;export{ColumnEnum,LoadingStatus,ModuleNameEnum,ScrollDirectionEnum,ProductSeriesEnum,}from./src/main/ets/constant/CommonEnums;export{defaultasLogger}from./src/main/ets/util/Logger;export{IPageContext,PageContext}from./src/main/ets/routermanager/PageContext;export{WindowUtil,StatusBarColorType,ScreenOrientation}from./src/main/ets/util/WindowUtil;export{BaseState}from./src/main/ets/viewmodel/BaseState;export{BaseVM}from./src/main/ets/viewmodel/BaseVM;export{BaseVMEvent}from./src/main/ets/viewmodel/BaseVMEvent;export{PreferenceManager}from./src/main/ets/storagemanager/PreferenceManager;export{TodoItem,TodoDatabase}from./src/main/ets/manager/TodoDatabase;export{GiftExchange,GiftExchangeDatabase}from./src/main/ets/manager/GiftExchangeDatabase;export{BreakpointTypeEnum,GlobalInfoModel}from./src/main/ets/model/GlobalInfoModel;export{ProcessUtil}from./src/main/ets/util/ProcessUtil;export{DbUtil}from./src/main/ets/util/Dbutil;export{RecordUtils}from./src/main/ets/util/RecordUtils;export{GlobalUIAbilityContext}from./src/main/ets/util/ContextConfig;export{PoemReader}from./src/main/ets/util/PoemReader;export{BreakpointSystem,BreakpointType}from./src/main/ets/util/BreakpointSystem;// UI 组件export{TopNavigationData,TopNavigationView}from./src/main/ets/component/TopNavigationView;export{CardItem}from./src/main/ets/component/CardItem;export{TimerComponent,TimerComponentController}from./src/main/ets/component/TimerComponent;export{CustomImageToggle}from./src/main/ets/component/CustomImageToggle;export{IconText}from./src/main/ets/component/IconText;export{TopBar}from./src/main/ets/component/TopBar;export{LoadingView}from./src/main/ets/component/LoadingView;export{BackupManagerService}from./src/main/ets/manager/BackupManagerService;// 数据模型export{AgentInfoData}from./src/main/ets/data/AgentInfoData;export{ChatData,ChatResponseData,DeltaData}from./src/main/ets/data/...;export{PoemDatabase,PoemItem}from./src/main/ets/db/PoemDatabase;network/Index.ets// network/Index.etsexport{PostRequest}from./src/main/ets/HttpRequest;export{HttpManager,RequestOptions}from./src/main/ets/HttpManager;export{ApiHttpManager}from./src/main/ets/ApiHttpManager;export{ChatResultData}from./src/main/ets/ChatResultData;export{CommonResponseModel}from./src/main/ets/common/CommonResponseModel;export{UrlConstants,LoadingStatus}from./src/main/ets/common/UrlConstants;feature 模块导出各业务模块只导出视图组件保持接口精简// feature/chat/Index.etsexport{ChatHomePage}from./src/main/ets/view/ChatHomePage;export{ChatView}from./src/main/ets/view/ChatView;// feature/stroke/Index.etsexport{StrokePage}from./src/main/ets/view/StrokePage;export{StrokeView}from./src/main/ets/view/StrokeView;// feature/my/Index.etsexport{MineView}from./src/main/ets/view/MineView;// feature/todo/Index.etsexport{TodoView}from./src/main/ets/view/TodoView;在 entry 的 HomePage 中直接引用import{ChatView}fromchat;import{MineView}frommy;import{StrokeView}fromstroke;import{TodoView}fromtodo;import{PageContext,GlobalUIAbilityContext}fromcommon;五、module.json5 配置module.json5定义模块的元信息、类型、设备支持和路由等。Entry 模块配置// entry/src/main/module.json5 { module: { name: entry, type: entry, mainElement: EntryAbility, deviceTypes: [phone, tablet, 2in1], deliveryWithInstall: true, pages: $profile:main_pages, routerMap: $profile:router_map, abilities: [ { name: EntryAbility, srcEntry: ./ets/entryability/EntryAbility.ets, exported: true, skills: [{ entities: [entity.system.home], actions: [ohos.want.action.home] }] } ], requestPermissions: [ { name: ohos.permission.INTERNET }, { name: ohos.permission.MICROPHONE, reason: $string:attention, usedScene: { abilities: [EntryAbility], when: inuse } } ] } }关键字段说明type:entry表示入口模块一个应用只能有一个 entrydeviceTypes: 支持的设备类型phone、tablet、2in1覆盖全场景pages: 页面路由配置文件引用routerMap: Navigation 路由表引用abilities: 声明的 UIAbility 列表HAR 模块配置// feature/chat/src/main/module.json5 { module: { name: chat, type: har, routerMap: $profile:router_map, deviceTypes: [default, tablet, 2in1] } }HAR 模块配置更简洁无需声明 abilities 和 pages但可以声明routerMap以支持 Navigation 路由跳转。deviceTypes中的default表示支持所有默认设备类型。六、模块化最佳实践依赖方向单向化严格遵循 entry → feature → network → common 的依赖链绝不反向依赖Index.ets 精简导出只导出其他模块需要使用的 API内部实现细节不暴露HAR 与 HSP 选择当前项目 feature 模块使用 HAR若多个模块引用同一 feature 且包体积敏感可迁移为 HSProuterMap 分模块声明每个 feature 模块独立维护自己的路由表entry 模块的路由表会自动合并common 层保持纯粹common 不依赖任何业务模块只提供基础设施能力小结柚兔学伴的多模块架构将应用拆分为 entry入口、common基础、network网络和多个 feature业务模块通过oh-package.json5的file:协议声明本地依赖通过Index.ets统一导出 API通过module.json5配置模块类型与能力。这种架构使代码职责清晰、依赖关系明确为多人协作和持续迭代奠定了坚实基础。