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

多模块架构设计与 HSP/HAR 模块化

在 HarmonyOS 应用开发中,随着业务复杂度的增长,单模块工程往往难以满足代码组织、团队协作和构建效率的需求。柚兔学伴项目采用了多模块架构,将不同业务和基础设施拆分为独立模块,实现了清晰的职责划分与灵活的依赖管理。本文将深入剖析 HarmonyOS 的模块体系以及柚兔学伴的模块化实践。

一、HarmonyOS 模块类型

HarmonyOS 提供了三种模块类型,适用于不同场景:

类型 全称 编译方式 运行时共享 适用场景
Entry 入口模块 独立编译为 HAP 仅自身使用 应用主模块,包含 UIAbility
HSP Harmony Shared Package 动态共享包 运行时单实例共享 多模块共享代码,减小包体积
HAR Harmony 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)等
  • network:HTTP 请求封装,包含 HttpManager、ApiHttpManager、URL 常量、响应模型
  • feature/todo:学习任务管理,诗词、课本、PDF 阅读
  • feature/stroke:笔画书写练习
  • feature/chat:AI 智能对话
  • feature/my:个人中心、积分、设置、关于

三、oh-package.json5 依赖配置

模块间的依赖关系通过每个模块的 oh-package.json5 声明。本地模块引用使用 "file:" 协议,指向相对路径。

entry 模块的依赖

entry 作为入口,依赖所有业务模块:

json5 复制代码
// 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:

json5 复制代码
// feature/chat/oh-package.json5
{
  "name": "chat",
  "version": "1.0.0",
  "main": "Index.ets",
  "dependencies": {
    "common": "file:../../common",
    "network": "file:../../network"
  }
}
json5 复制代码
// 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:

json5 复制代码
// 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.ets

common 作为基础层,导出量最大:

typescript 复制代码
// common/Index.ets
export { 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 { default as Logger } 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

typescript 复制代码
// network/Index.ets
export { 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 模块导出

各业务模块只导出视图组件,保持接口精简:

typescript 复制代码
// feature/chat/Index.ets
export { ChatHomePage } from './src/main/ets/view/ChatHomePage';
export { ChatView } from './src/main/ets/view/ChatView';

// feature/stroke/Index.ets
export { StrokePage } from './src/main/ets/view/StrokePage';
export { StrokeView } from './src/main/ets/view/StrokeView';

// feature/my/Index.ets
export { MineView } from './src/main/ets/view/MineView';

// feature/todo/Index.ets
export { TodoView } from './src/main/ets/view/TodoView';

在 entry 的 HomePage 中直接引用:

typescript 复制代码
import { ChatView } from 'chat';
import { MineView } from 'my';
import { StrokeView } from 'stroke';
import { TodoView } from 'todo';
import { PageContext, GlobalUIAbilityContext } from 'common';

五、module.json5 配置

module.json5 定义模块的元信息、类型、设备支持和路由等。

Entry 模块配置

json5 复制代码
// 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" 表示入口模块,一个应用只能有一个 entry
  • deviceTypes : 支持的设备类型,phonetablet2in1 覆盖全场景
  • pages: 页面路由配置文件引用
  • routerMap: Navigation 路由表引用
  • abilities: 声明的 UIAbility 列表

HAR 模块配置

json5 复制代码
// 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" 表示支持所有默认设备类型。

六、模块化最佳实践

  1. 依赖方向单向化:严格遵循 entry → feature → network → common 的依赖链,绝不反向依赖
  2. Index.ets 精简导出:只导出其他模块需要使用的 API,内部实现细节不暴露
  3. HAR 与 HSP 选择:当前项目 feature 模块使用 HAR,若多个模块引用同一 feature 且包体积敏感,可迁移为 HSP
  4. routerMap 分模块声明:每个 feature 模块独立维护自己的路由表,entry 模块的路由表会自动合并
  5. common 层保持纯粹:common 不依赖任何业务模块,只提供基础设施能力

小结

柚兔学伴的多模块架构将应用拆分为 entry(入口)、common(基础)、network(网络)和多个 feature(业务)模块,通过 oh-package.json5"file:" 协议声明本地依赖,通过 Index.ets 统一导出 API,通过 module.json5 配置模块类型与能力。这种架构使代码职责清晰、依赖关系明确,为多人协作和持续迭代奠定了坚实基础。

相关推荐
不才难以繁此生1 小时前
ArkUI Tabs 切换后状态丢失怎么办:中式美食分类页怎么保留关键词、筛选和滚动位置
harmonyos·状态管理·arkui·tabs·中式美食
爱吃大芒果15 小时前
复刻 HarmonyKit 工具箱:基于新版 @kit 开发本地工具 App
华为·harmonyos
风华圆舞15 小时前
鸿蒙上跑通第一个 AI Agent:5 分钟接入智谱/DeepSeek
人工智能·华为·harmonyos·arkts·arkui·toolregistry
xd18557855516 小时前
电影匹配引擎-基于鸿蒙的心情电影推荐应用开发实践
人工智能·安全·华为·harmonyos·鸿蒙
千逐6817 小时前
HarmonyOS 实战 | @State 不神秘——变量一变界面就跟着变
华为·harmonyos·鸿蒙
不才难以繁此生18 小时前
NavPathStack 返回错页怎么排查:中式美食详情页从搜索、收藏和推荐进入怎么回到原处
harmonyos·arkts·arkui·中式美食·navpathstack
xd18557855520 小时前
梦境解析师-基于鸿蒙的梦境心理分析应用开发实践
人工智能·华为·harmonyos·鸿蒙
千逐6821 小时前
鸿蒙实战:一多自适应与原子化布局 —— 一次开发多端部署的工程化落地
华为·harmonyos·鸿蒙
解局易否结局1 天前
鸿蒙原生开发实战:Native 并发与高性能计算
华为·harmonyos