当前位置: 首页 > news >正文

HarmonyOS APP《画伴梦工厂》开发第43篇-多模块架构设计——模块拆分与依赖管理

第6.1篇:多模块架构设计——模块拆分与依赖管理

难度:⭐⭐⭐ 高级
前置知识:第 1.1 篇 ArkTS 入门
涉及源文件build-profile.json5(根)、oh-package.json5(根)、products/default/oh-package.json5products/default/module.json5common/oh-package.json5features/adaptiveLayout/oh-package.json5features/responsiveLayout/oh-package.json5common/Index.ets


一、概述

在"画伴梦工厂"项目中,随着功能不断扩展——自适应布局、响应式布局、语音识别、3D 渲染、服务卡片等——单模块架构逐渐暴露出以下问题:

痛点表现
编译速度慢任何微小改动都需要重新编译整个工程
耦合严重工具函数、常量、类型定义散落在各个页面目录下,难以复用
职责边界模糊布局逻辑与业务逻辑混在一起,修改一个功能可能影响其他功能
不利于团队协作多人同时修改同一模块极易产生代码冲突

为了解决这些问题,项目采用了多模块(Multi-Module)架构。多模块架构是鸿蒙工程中一种成熟的代码组织方式,它将代码按职责拆分为多个独立的模块,每个模块拥有自己的oh-package.json5依赖声明和build-profile.json5注册项,模块之间通过file:协议建立显式的依赖关系。

本文将深入分析"画伴梦工厂"的多模块工程结构,从build-profile.json5的模块注册、oh-package.json5的跨模块依赖声明、module.json5的模块配置等维度,完整阐述鸿蒙多模块架构的设计思路与最佳实践。


二、四模块架构总览

项目共拆分为4 个模块,职责划分如下:

drawing-main/ ├── common/ # 共享基础库(Shared Library) │ └── oh-package.json5 # name: @ohos/common ├── features/ │ ├── adaptiveLayout/ # 自适应布局特性(Feature Library) │ │ └── oh-package.json5 # name: @ohos/adaptivelayout │ └── responsiveLayout/ # 响应式布局特性(Feature Library) │ └── oh-package.json5 # name: @ohos/responsivelayout └── products/ └── default/ # 主应用入口模块(Entry Module) ├── oh-package.json5 # 依赖所有其他模块 ├── module.json5 # type: entry └── src/main/ets/ # 应用代码

2.1 common —— 共享基础库

common模块是所有其他模块的公共依赖。它不包含任何业务逻辑,只提供项目范围内的共享基础能力:

能力文件说明
Loggercommon/src/main/ets/utils/Logger.ets基于@kit.PerformanceAnalysisKit的日志封装,提供 debug/info/warn/error 分级输出
BreakpointSystemcommon/src/main/ets/utils/BreakpointSystem.ets基于mediaquery的断点系统,监测屏幕尺寸变化并同步到AppStorage
BreakPointType<T>同上文件的导出类泛型工具,根据当前断点名称返回对应的配置值

common模块通过Index.ets作为统一出口导出所有公共 API:

// common/Index.etsexport{Logger}from'./src/main/ets/utils/Logger';export{BreakpointSystem,BreakPointType}from'./src/main/ets/utils/BreakpointSystem';

2.2 adaptiveLayout —— 自适应布局特性

adaptiveLayout模块封装了基于BreakpointSystem的自适应布局组件和工具函数。它依赖common模块获取断点状态,并对外暴露adaptiveLayout组件:

// features/adaptiveLayout/Index.etsexport{adaptiveLayout}from'./src/main/ets/pages/AdaptiveLayout';

2.3 responsiveLayout —— 响应式布局特性

responsiveLayout模块封装了基于GridRow/GridCol的响应式网格布局组件。同样依赖common模块,对外暴露responsiveLayout组件:

// features/responsiveLayout/Index.etsexport{responsiveLayout}from'./src/main/ets/pages/ResponsiveLayout';

2.4 default —— 主应用入口

default模块是type: "entry"的主应用模块,包含所有页面、Ability、服务卡片、权限声明等。它是唯一可以打包运行的模块,聚合了所有特性模块的能力。


三、模块依赖关系图

四个模块之间的依赖关系形成一个清晰的有向无环图(DAG)

┌──────────────────────────────────────┐ │ default (entry) │ │ products/default/oh-package.json5 │ └──────┬────────────────────┬───────────┘ │ │ depends on depends on │ │ ▼ ▼ ┌────────────────────┐ ┌────────────────────────┐ │ adaptiveLayout │ │ responsiveLayout │ │ (feature library) │ │ (feature library) │ └────────┬───────────┘ └───────────┬────────────┘ │ │ depends on depends on │ │ ▼ ▼ ┌──────────────────────────────────────────┐ │ common (shared) │ │ @ohos/common : 1.0.0 │ └──────────────────────────────────────────┘

这个依赖图遵循了单向依赖原则:

  • common不依赖任何模块
  • adaptiveLayoutresponsiveLayout只依赖common
  • default依赖所有其他模块

任何两个模块之间都不存在循环依赖,这是多模块架构能够正常编译的基本前提。


四、根 build-profile.json5 —— 模块注册中心

build-profile.json5是鸿蒙工程的模块注册配置文件,它声明了项目包含的所有模块及其路径。在"画伴梦工厂"中,根build-profile.json5的核心结构如下:

{ "app": { "products": [{ "name": "default", "targetSdkVersion": "6.0.0(20)", "compatibleSdkVersion": "6.0.0(20)", "runtimeOS": "HarmonyOS" }], "buildModeSet": [{ "name": "debug" }, { "name": "release" }] }, "modules": [ { "name": "default", "srcPath": "./products/default" }, { "name": "common", "srcPath": "./common" }, { "name": "adaptiveLayout", "srcPath": "./features/adaptiveLayout" }, { "name": "responsiveLayout", "srcPath": "./features/responsiveLayout" } ] }

4.1 modules 数组

每一个modules条目定义了一个模块:

字段说明
name模块名称,在项目中必须唯一,用于在构建系统中标识模块
srcPath模块源码根目录的相对路径(相对于项目根目录)

注意:模块的nameoh-package.json5中的name字段可以不同build-profile.json5中的name是构建系统使用的标识符,而oh-package.json5中的name是跨模块依赖时引用的包名。

4.2 app.products 与 app.buildModeSet

  • products:定义了产品的构建产物配置。targetSdkVersioncompatibleSdkVersion分别指定目标 SDK 版本和兼容 SDK 版本。runtimeOS指定运行的操作系统。
  • buildModeSet:定义可用的构建模式,包括debug(调试模式,包含调试符号和日志)和release(发布模式,混淆和优化后发布)。

五、oh-package.json5 跨模块依赖声明

5.1 根 oh-package.json5

根目录的oh-package.json5声明了项目全局的依赖:

{ "modelVersion": "6.0.0", "description": "Please describe the basic information.", "dependencies": {}, "devDependencies": { "@ohos/hypium": "1.0.24", "@ohos/hamock": "1.0.0" } }

devDependencies中的@ohos/hypium@ohos/hamock是测试框架依赖,仅在开发环境使用,不会打包到最终产物中。

5.2 entry 模块的依赖声明

products/default/oh-package.json5声明了主模块对三个子模块的依赖:

{ "name": "default", "version": "1.0.0", "main": "", "dependencies": { "@ohos/adaptivelayout": "file:../../features/adaptiveLayout", "@ohos/responsivelayout": "file:../../features/responsiveLayout", "@ohos/common": "file:../../common" } }

这里的file:协议是鸿蒙工程中跨模块依赖的关键语法。"file:../../features/adaptiveLayout"表示依赖指向features/adaptiveLayout目录下的模块,构建系统会根据该目录下的oh-package.json5中的name字段解析包名。

5.3 common 模块的依赖声明

{ "name": "@ohos/common", "version": "1.0.0", "main": "Index.ets", "dependencies": {} }

关键点:

  • name@ohos/common,这是其他模块依赖它时使用的包名
  • main指定为Index.ets,这是模块的入口文件,其他模块通过import { ... } from '@ohos/common'导入时,实际上导入的是Index.ets中导出的内容
  • dependencies为空,common是依赖链的最底层

5.4 特性模块的依赖声明

adaptiveLayout为例:

{ "name": "@ohos/adaptivelayout", "version": "1.0.0", "main": "Index.ets", "dependencies": { "@ohos/common": "file:../../common" } }

responsiveLayout的配置与之类似,同样依赖@ohos/common

5.5 file: 协议详解

file:协议是 HarmonyOS 提供的本地模块引用机制,语法为"file:<相对路径>"。其核心特性包括:

特性说明
路径解析相对路径从当前oh-package.json5所在目录开始计算
自动依赖传递依赖 A 的模块自动获得 A 所依赖的 B 的能力,无需额外声明
编译时链接构建系统在编译阶段将本地模块的代码链接到最终产物中
版本无关本地模块的version字段不影响依赖解析,始终使用本地源码

六、module.json5 模块配置详解

products/default/src/main/module.json5entry 模块的核心配置文件,它定义了模块的类型、支持的设备、页面路由、Ability 组件以及权限声明:

{ "module": { "name": "default", "type": "entry", "description": "$string:module_desc", "mainElement": "DefaultAbility", "deviceTypes": ["phone", "tablet", "2in1"], "deliveryWithInstall": true, "installationFree": false, "pages": "$profile:main_pages", "requestPermissions": [ { "name": "ohos.permission.INTERNET" }, { "name": "ohos.permission.CAMERA", "reason": "$string:camera_reason", "usedScene": { "abilities": ["DefaultAbility"], "when": "inuse" } }, { "name": "ohos.permission.MICROPHONE", "reason": "$string:microphone_reason", "usedScene": { "abilities": ["DefaultAbility"], "when": "inuse" } }, { "name": "ohos.permission.DISTRIBUTED_DATASYNC", "reason": "$string:distributed_data_reason", "usedScene": { "abilities": ["DefaultAbility"], "when": "inuse" } } ], "abilities": [ { "name": "DefaultAbility", "srcEntry": "./ets/defaultability/DefaultAbility.ets", "description": "$string:ability_desc", "icon": "$media:layered_image", "label": "$string:ability_label", "startWindowIcon": "$media:startIcon", "startWindowBackground": "$color:start_window_background", "exported": true, "skills": [{ "entities": ["entity.system.home"], "actions": ["ohos.want.action.home"] }] } ], "extensionAbilities": [ { "name": "CreationFormAbility", "srcEntry": "./ets/creationformability/CreationFormAbility.ets", "type": "form", "metadata": [{ "name": "ohos.extension.form", "resource": "$profile:form_config" }] }, { "name": "DefaultBackupAbility", "srcEntry": "./ets/defaultbackupability/DefaultBackupAbility.ets", "type": "backup", "exported": false, "metadata": [{ "name": "ohos.extension.backup", "resource": "$profile:backup_config" }] } ] } }

6.1 关键字段解读

字段含义
name"default"模块名称,与build-profile.json5中的name对应
type"entry"模块类型,entry 表示可独立运行的应用入口模块
deviceTypes["phone", "tablet", "2in1"]目标设备类型,支持手机、平板和二合一设备
pages"$profile:main_pages"页面路由配置,指向 resources/base/profile/main_pages.json
mainElement"DefaultAbility"应用入口 Ability

6.2 requestPermissions —— 安全权限声明

项目声明了四种权限:

  1. INTERNET:网络访问权限,用于图片上传和 API 调用
  2. CAMERA:相机权限,用于拍照采集画作,仅在inuse(前台使用时)申请
  3. MICROPHONE:麦克风权限,用于语音识别功能
  4. DISTRIBUTED_DATASYNC:分布式数据同步权限,用于跨设备数据共享

每个危险权限都附带了reason字符串资源,在权限申请弹窗中向用户说明使用目的,这符合鸿蒙的安全最佳实践。

6.3 extensionAbilities —— 扩展能力

  • CreationFormAbility(type:form):服务卡片 Ability,提供桌面小组件功能
  • DefaultBackupAbility(type:backup):数据备份 Ability,支持应用数据的云备份与恢复

七、模块类型详解:entry / feature / shared

在鸿蒙多模块架构中,模块按职责分为三种类型:

7.1 entry 模块

{ "type": "entry" }
  • 用途:应用的主入口模块,包含 Ability、页面路由、权限声明等应用级配置
  • 特性
    • 只能有一个 entry 模块(在build-profile.json5products中定义)
    • 必须包含module.json5type"entry"
    • 可以引用所有 feature 和 shared 模块
    • 最终生成可安装的 HAP 包

在项目中,products/default就是 entry 模块,它负责聚合所有特性模块并提供最终的 UI 页面和应用生命周期管理。

7.2 feature 模块

feature 模块没有独立的module.json5,而是通过oh-package.json5声明自身并提供导出。

  • 用途:封装独立的业务特性或功能,如自适应布局、响应式布局
  • 特性
    • 可以有多个 feature 模块
    • 可以依赖 shared 模块和其他 feature 模块
    • 不包含 Ability 或页面路由配置
    • 通过Index.ets对外暴露 API

项目中features/adaptiveLayoutfeatures/responsiveLayout都是 feature 模块,两者职责清晰、互不依赖。

7.3 shared 模块

  • 用途:提供跨模块共享的基础能力,如工具类、常量、日志等
  • 特性
    • 可以有多个 shared 模块
    • 不应依赖任何 feature 模块(保持最底层位置)
    • 通过Index.ets作为模块入口统一导出

项目中的common模块是典型的 shared 模块,它不依赖任何其他业务模块,其他所有模块都可以引用它。


八、Index.ets —— 模块入口约定

在鸿蒙多模块架构中,每个通过oh-package.json5导出的模块都需要指定一个入口文件main字段)。common模块的入口文件如下:

// common/Index.etsexport{Logger}from'./src/main/ets/utils/Logger';export{BreakpointSystem,BreakPointType}from'./src/main/ets/utils/BreakpointSystem';

这种做法形成了清晰的门面模式(Facade Pattern)

  • 对外隐藏内部实现细节:其他模块只需关心Index.ets中导出了什么,无需了解utils/目录的组织结构
  • 统一引用入口import { Logger } from '@ohos/common'即可获取日志能力
  • 控制可访问性Index.ets中只导出需要暴露的 API,内部类和常量不对外可见

九、common 模块核心能力剖析

9.1 Logger —— 统一日志服务

import{hilog}from'@kit.PerformanceAnalysisKit';exportclassLogger{privatereadonlyprefix:string='testTag';privatereadonlydomain:number=0xFF00;privatereadonlyformat:string='%{public}s, %{public}s';publicdebug(...args:string[]):void{hilog.debug(this.domain,this.prefix,this.format,args);}publicinfo(...args:string[]):void{hilog.info(this.domain,this.prefix,this.format,args);}publicwarn(...args:string[]):void{hilog.warn(this.domain,this.prefix,this.format,args);}publicerror(...args:string[]):void{hilog.error(this.domain,this.prefix,this.format,args);}}

Logger封装了鸿蒙的hilog日志接口,提供了debuginfowarnerror四个等级的输出方法。所有模块统一使用这个 Logger,避免了日志输出格式不一致的问题。

9.2 BreakpointSystem —— 媒体查询断点系统

BreakpointSystem是自适应布局的核心基础设施。它通过mediaquery.MediaQueryListener监听屏幕宽度变化,并在断点切换时更新AppStorage中的全局状态:

exportclassBreakpointSystem{privatereadonlybreakpoints:Breakpoint[]=[{name:'sm',size:320},{name:'md',size:600},{name:'lg',size:840},{name:'xl',size:1080}];publicregister(uiContext:UIContext):void{// 为每个断点范围注册媒体查询监听器this.breakpoints.forEach((breakpoint,index)=>{letcondition='';if(index===this.breakpoints.length-1){condition=`(${breakpoint.size}vp<=width)`;}else{condition=`(${breakpoint.size}vp<=width<${this.breakpoints[index+1].size}vp)`;}// ... 注册监听});}}

common模块还将BreakPointType<T>泛型工具类一并导出,使得特性模块可以根据当前断点名称获取对应的配置值(如间距、字号等),实现真正的响应式布局。

9.3 为什么不把这些放在 entry 模块?

将 Logger 和 BreakpointSystem 放在common模块而非default模块,是基于以下架构考量:

  1. 避免循环依赖:如果 Logger 放在default模块中,那么adaptiveLayout要使用 Logger 就必须依赖default,而default又依赖adaptiveLayout,形成循环依赖,违反 DAG 原则。

  2. 模块复用性common模块可以独立复用。如果将来项目需要增加一个wearable产品线,只需在build-profile.json5中注册新的 entry 模块,并复用已有的commonfeatures/*模块。

  3. 编译效率common模块的内容不常变更,编译一次后可以被缓存,后续重新编译其他模块时无需重新编译common,显著提升增量编译速度。


十、架构决策原理与最佳实践

10.1 为什么选择多模块架构?

单模块架构(不采用) 多模块架构(采用) ┌─────────────────────┐ ┌─────────────────────┐ │ 所有代码混在一起 │ │ clear: entry │ │ 大到难以维护 │ │ │ │ │ 编译需要 5 分钟 │ │ ├─ feature: 布局 │ │ 改一行全局重编 │ │ ├─ feature: 语音 │ │ 新人上手困难 │ │ └─ shared: common │ └─────────────────────┘ │ 编译只需 1-2 分钟 │ │ 模块职责清晰 │ │ 可独立开发和测试 │ └─────────────────────┘

10.2 模块拆分原则

在实际项目中,建议遵循以下原则进行模块拆分:

原则说明项目中的体现
单一职责每个模块只做一件事common只做共享基础库,adaptiveLayout只做自适应布局
无环依赖依赖图必须为 DAGcommon ← adaptiveLayout ← default
接口隔离通过Index.ets控制导出范围只导出需要公开的 API
稳定方向依赖更稳定的模块被更低层依赖common最稳定,位于底层
共同复用一起变化的类放在同一模块布局相关组件集中在各自 feature 模块

10.3 常见的架构陷阱

陷阱一:过度拆分

模块的数量不是越多越好。通常 3~8 个模块对于中型项目是比较合理的区间。如果模块粒度过细(每个工具类一个模块),反而会增加依赖管理的复杂度。

陷阱二:循环依赖

鸿蒙构建系统不支持循环依赖。如果 A 依赖 B、B 依赖 C、C 又依赖 A,编译会直接报错。解决方法是:将循环双方的共同依赖抽离到一个新的 shared 模块中。

陷阱三:跨模块直接引用内部文件

// ❌ 错误做法——跨模块引用内部路径import{Logger}from'../../common/src/main/ets/utils/Logger';
// ✅ 正确做法——通过模块名引用import{Logger}from'@ohos/common';

直接引用内部路径会绕过模块的Index.ets入口,导致模块的封装性被破坏。如果以后重构内部文件结构,所有直接引用的地方都需要修改。

10.4 构建性能优化

多模块架构带来的一个核心收益是增量编译。在鸿蒙 DevEco Studio 中,当修改features/adaptiveLayout的代码时:

  1. 构建系统检测到adaptiveLayout的源文件发生变更
  2. 仅重新编译adaptiveLayout模块及其直接依赖者(如default
  3. commonresponsiveLayout模块无需重新编译

对于大型项目,这种增量编译可以将构建时间从数分钟降低到数十秒。


总结

本文通过"画伴梦工厂"的实际项目代码,完整分析了鸿蒙多模块架构的设计与实现:

知识点对应文件/配置核心要点
模块注册build-profile.json5modules数组注册所有模块,products定义构建产物
依赖声明oh-package.json5file:协议声明本地模块依赖,name/main定义模块入口
模块配置module.json5type: entry定义入口模块,deviceTypes指定支持设备
模块类型三者搭配使用entry(主应用)、feature(特性库)、shared(共享库)
模块入口Index.ets门面模式统一导出,隐藏内部实现
共享能力common模块提供 Logger、BreakpointSystem 等跨模块基础设施
依赖图整体结构DAG 单向依赖,无循环引用
最佳实践架构原则单一职责、接口隔离、稳定方向依赖

多模块架构是鸿蒙工程从"能跑就行"迈向"可维护、可扩展"的关键一步。它为项目的持续迭代奠定了坚实的工程基础,也是团队协作开发的必备架构模式。

下一篇:第 6.2 篇将探讨鸿蒙工程的构建配置进阶——多产物构建、签名管理与 CI/CD 流水线集成,敬请期待。

http://www.jsqmd.com/news/1142614/

相关文章:

  • 计算机毕业设计之基于大数据的互联网招聘网站数据分析
  • 2026中山黄金回收白银回收铂金回收旧料回收怎么选?五家高实价铂金白银线下门店测评清单 + 联系方式
  • 2026年AI聚合API平台深度评测:企业与开发者如何选择稳定的模型调度中枢
  • Vue3 环境搭建 + 第一个 HelloVue 项目(零基础入门)
  • P17062 [JRKSJ R10 热身赛] Captain 题解就是用来C的
  • AI Agent 重试机制:模型调用失败后,退避策略怎么写才靠谱
  • 基于Wireshark抓包与算法分析的PT站流量作弊检测实战
  • 3步实现Windows经典游戏兼容性修复的终极指南
  • 终极指南:15分钟搞定黑苹果EFI配置,OpCore Simplify让复杂技术变得简单
  • 计算机毕业设计之基于SSM的热点个性化推荐新闻
  • 计算机毕业设计之公共自行车数据分布式存储与计算
  • python6.6-函数的默认参数
  • Obsidian系列8:第三方插件的下载安装和使用
  • 政务云平台建设全解析:一朵云如何管住200+应用、上千核算力?(PPT)
  • 手机号关联QQ查询:揭秘Python逆向协议的高效解决方案
  • 2026 AI标书软件趋势
  • ADP5350与MK64FN1M0VDC12的智能电源管理方案
  • 2026昭通黄金回收白银回收铂金回收旧料回收怎么选?五家高实价铂金白银线下门店测评清单 + 联系方式
  • Stable-Diffusion-WebUI 1.9.2 安装:Windows 10/11 双系统 3 步环境验证与常见报错修复
  • 成都专业的中央空调公司哪家可靠
  • Kindle Comic Converter完全指南:5分钟将漫画转为Kindle专属格式
  • Gemini3.5 营销分析教程:竞品资料、用户反馈和推广方案拆解
  • 2026亳州黄金回收白银回收铂金回收工商备案可查全城上门回收旧金老店联系方式推荐
  • 微软Anthropic狂砸千亿,钱花在哪?Claude跨产品防护机制公开,73% PR已由AI生成
  • Edge浏览器卸载不干净怎么办?Windows命令行清除残留完整方法
  • 如何用Mermaid图表工具快速提升技术文档质量:7天掌握文本驱动可视化的完整指南
  • Windows字体自定义终极指南:免费恢复系统界面字体设置
  • 口碑佳的电脑上门维修,究竟哪家技术更胜一筹?
  • 不同AI平台,不同玩法——DeepSeek、豆包、Kimi、通义千问的GEO差异
  • linux系统下用什么语言写B/S系统比较好