【ArkUI 练中学】第11课:应用架构与模块化开发
本节目标
· 理解 HAP、HAR、HSP 三种包类型的核心区别与适用场景,能够根据业务需求正确选型
· 掌握 HAR 静态共享包的创建、导出与引用方法,实现代码与资源的跨模块复用
· 掌握 HSP 动态共享包的创建与引用方法,理解其在资源复用与按需加载中的价值
· 理解应用分层架构设计思想,掌握产品定制层、基础特性层、公共能力层的职责划分
· 理解 MVVM 模式在 ArkUI 中的落地方式,明确 Model、View、ViewModel 的边界与协作关系
· 掌握模块化拆分的核心原则,避免“为拆分而拆分”的反模式
· 能够为一个中型应用设计合理的模块化架构方案
一、应用程序包结构概述
1.1 三种包类型
HarmonyOS 应用以 App Pack 形式发布,App Pack 由多个包组成。根据功能定位和编译方式的不同,这些包分为三种类型:HAP、HAR 和 HSP。
HAP(Harmony Ability Package) 是应用安装和运行的基本单元,包含应用的代码、资源、配置等文件。HAP 可分为 Entry 和 Feature 两种类型:Entry 类型的 HAP 是应用的主模块,包含启动图标和核心功能,同一设备类型仅有一个;Feature 类型的 HAP 是动态扩展功能模块,数量不限。
HAR(Harmony Archive) 是静态共享包,可以包含代码、C++库、资源和配置文件。通过 HAR 可以实现多个模块或多个工程共享 ArkUI 组件、资源等相关代码。HAR 不同于 HAP,不能独立安装运行在设备上,只能作为应用模块的依赖项被引用。
HSP(Harmony Shared Package) 是动态共享包,同样可以包含代码、C++库、资源和配置文件。通过 HSP 可以实现代码和资源的共享,HSP 不支持独立发布,而是跟随其宿主应用的 APP 包一起发布,与宿主应用同进程,具有相同的包名和生命周期。
1.2 三种包类型的核心对比
从编译方式看,HAR 随使用方编译,多副本存在;HSP 独立编译,单副本运行。从运行方式看,HAR 是静态加载,HSP 是动态加载。从发布范围看,HAR 跨应用可用,HSP 仅限应用内或集成态可用。
从资源复用角度看,多包(HAP/HSP)引用相同的 HAR 时,会造成多包间代码和资源的重复拷贝,从而导致应用包变大。HSP 则能在运行时复用,进程内只存一份,有效减少重复打包。
关键区别:HAR 解决的是“开发态代码复用”问题,HSP 解决的是“运行态资源复用”问题。HSP 开发时会同时生成 .hsp 和 .har 文件,后者作为接口文件供使用方引用。
二、HAR 静态共享包
2.1 创建 HAR 模块
在 DevEco Studio 中创建 HAR 模块的步骤如下:鼠标移到工程目录顶部,单击右键,选择 New > Module;在 Choose Your Ability Template 界面中,选择 Static Library,并单击 Next;在 Configure New Module 界面中,设置新添加的模块信息,设置完成后,单击 Finish 完成创建。
创建完成后,HAR 模块的工程结构中会包含 Index.ets 文件,这是共享包导出声明的入口。此外还可能包含 libs 目录(存放 .so 文件)、src > main > cpp 目录(存放 C++ 代码和 CMake 配置文件)等。
2.2 导出与引用 HAR
开发完 HAR 模块后,通过 DevEco Studio 菜单栏的 Build > Make Module ${libraryName} 进行编译构建,生成 HAR 文件。HAR 可供工程其他模块引用,或将 HAR 上传至 ohpm 仓库,供其他开发者下载使用。
在 HAR 模块的 Index.ets 中导出对外暴露的接口:
// library/Index.ets
export { formatDate, formatPrice } from './src/main/ets/utils/Formatter'
export { default as Logger } from './src/main/ets/utils/Logger'
使用方在 oh-package.json5 中配置依赖后,通过 import 引用 HAR 中的组件、方法或类,资源则通过 $r 引用。
2.3 HAR 的使用约束与注意事项
HAR 不能独立安装运行,只能作为应用模块的依赖项被引用。
HAR 中的 C++ 代码不会直接打包进 .har 文件,而是编译成动态依赖库 .so 文件放置在 .har 文件中的 libs 目录下。
编译构建 HAR 时会生成资源文件 ResourceTable.txt,以便编辑器可以对 HAR 中的资源文件进行联想。如果不使用 DevEco Studio 对 HAR 进行构建,编辑器将无法联想 HAR 中的资源。
开发 HAR 时建议开启混淆保护代码,在 build-profile.json5 中配置 “proguard”: true。
三、HSP 动态共享包
3.1 创建 HSP 模块
创建 HSP 模块的步骤与 HAR 类似,但在模板类型选择时选择 Shared Library。在 DevEco Studio 中,鼠标移到工程目录顶部,单击右键,选择 New > Module;模板类型选择 Shared Library,点击 Next;设置模块名称后,单击 Finish 完成创建。
3.2 HSP 的使用约束
HSP 及其使用方都必须是 API 10 及以上版本 Stage 模型,且都必须使用模块化编译模式。
HSP 分为应用内 HSP 和集成态 HSP 两种:应用内 HSP 在编译过程中与应用包名(bundleName)强耦合,只能给某个特定的应用使用;集成态 HSP 在构建、发布过程中不与特定的应用包名耦合,使用时工具链支持自动将集成态 HSP 的包名替换成宿主应用包名。
3.3 编译与引用 HSP
开发完 HSP 模块后,通过 Build > Make Module ${libraryName} 进行编译构建,生成 HSP。打包 HSP 时,会同时默认打包出 HAR,在模块下 build 目录下可以看到 .har 和 .hsp 文件。
如需在应用内共享 HSP,需要将 HSP 共享包上传至私仓。要使用 HSP 中的接口,首先需要在使用方的 oh-package.json5 中配置对它的依赖。
从 HSP 页面跳转时,router.pushUrl 的 url 格式为 ‘@bundle:包名(bundleName)/模块名(moduleName)/路径/页面所在的文件名(不加.ets后缀)’。如果从 HSP 页面返回 HAP 页面,url 的内容为 ‘pages/Index’。
3.4 HSP 的典型应用场景
当有多个安装包需要资源共享时,利用 HSP 可以减少公共资源和代码重复打包。对于部分功能需要按需动态下载的场景(如支付宝首页的骑行、菜鸟等模块),推荐使用 HSP。实测数据表明,将客服模块编译为 HSP 格式后,首次安装不包含在主包,可节省约 30% 的安装包体积。
跨 HAP 共享单例必须用 HSP,HAR 会导致多实例问题。
四、分层架构设计
4.1 三层架构概述
HarmonyOS 应用的分层架构主要包括三个层次:产品定制层、基础特性层和公共能力层。开发者可以根据实际应用的复杂度,在三层的基础上在各层内部二次分层。
产品定制层:不同设备的个性化业务,包含 UI、资源、配置,编译成不同设备 Entry 类型 HAP 包。开发者根据实际情况采用 Entry 分包还是共包。
基础特性层:抽象应用基础特性,每个特性高内聚、低耦合,灵活部署。需要单独部署的,设计为 Feature 类型的 HAP 包;不需要单独部署的,设计为 HAR 包或 HSP 包。
公共能力层:基础特性层依赖的公共能力,如 UI 组件、工具类,编译成 HAR 包或 HSP 包。
4.2 模块包类型实践
实践中,单 Entry HAP 包 + 多 HAR 包在比较常见,多见于单设备且没有动态部署要求的应用。HSP 如果是按需加载的场景推荐使用,否则还是推荐 HAR。
模块分包/共包建议:有桌面应用图标的应用,平板和 PC 差异化小,建议采用 Entry 共包方案;模块特性在不同设备上差异化较大的,建议采用分包方案;不同设备同一断点布局结构差异化大的,建议分包,反之共包。
4.3 MVVM 模式在 ArkUI 中的落地
ArkUI 采取 MVVM = Model + View + ViewModel 模式,其中状态管理模块起到的就是 ViewModel 的作用,将数据与视图绑定在一起,更新数据的时候直接更新视图。
View 层:在 ArkUI 中通常是 @Component 装饰组件渲染的 UI。
ViewModel 层:面向页面或业务场景,负责组装页面状态、调用 service/repository、暴露事件方法。一般放在 viewmodel 或 store 层,不放 model 层。
Model 层:只表达业务数据和数据访问结果,比如接口 DTO。不包含页面状态逻辑。
4.4 经典三层架构的职责划分
从更宏观的视角看,分层架构可以划分为:
UI 层(表现层) :ArkUI 组件、用户交互、状态渲染。处理用户界面和交互,不包含业务逻辑。
业务逻辑层(BLL) :数据转换、业务规则、流程编排。负责业务逻辑的处理和编排。
数据访问层(DAL) :网络请求、数据库操作、文件读写。负责数据的获取和持久化。
五、模块化拆分原则
5.1 核心原则
高内聚低耦合:每个模块应负责特定功能或特性,模块之间通过明确定义的接口通信,尽量减少直接依赖。
按功能拆分:把不同功能拆分成独立 Module(比如登录模块、支付模块),就像乐高积木一样自由组合。
按“UI 模块 + 服务模块”拆分:多设备/多模块协作时,可按 UI 模块 + 服务模块拆分,分别打包为 HAP,再通过 Build App 合并发布,降低耦合、便于独立测试与复用。
5.2 推荐策略
对于大部分项目,推荐采用 “单 HAP + 多 HAR” 的架构。HAR 在编译时会整体打包进 HAP,虽然略微增加包体积,但利用 ArkTS 的编译优化特性,可以实现代码裁剪和类型推断,性能损耗可控。
模块化编译基于 ES Module 的 Bundleless 编译模式,API 10 及以上版本的 Stage 模型工程默认开启。修改单个模块代码无需整包编译构建,增量编译构建时间极大减少。
5.3 避免反模式
避免为了拆分而拆分,否则维护成本会高于收益。模块划分应基于业务边界和团队协作需求,而非过度追求“小而美”。
跨 HAP 共享单例需用 HSP,HAR 会导致多实例问题。如果多个模块需要共享同一个单例对象(如全局配置管理器),应将其设计为 HSP 而非 HAR。
六、多元化习题
习题 1(判断题)
题目:HAR 静态共享包可以独立安装运行在设备上,而 HSP 动态共享包不能独立安装运行。
答案:错误
解读:HAR 和 HSP 都不能独立安装运行在设备上。HAR 只能作为应用模块的依赖项被引用,HSP 跟随其宿主应用的 APP 包一起发布,与宿主应用同进程。只有 HAP 才是应用安装和运行的基本单元。
习题 2(单选题)
题目:以下关于 HAR 和 HSP 的说法,正确的是( )
A. HAR 是动态共享包,HSP 是静态共享包
B. 多包引用相同的 HAR 时会造成代码和资源的重复拷贝
C. HSP 跨应用可用,HAR 仅限应用内使用
D. HSP 开发时不会生成 HAR 文件
答案:B
解读:HAR 是静态共享包,HSP 是动态共享包,选项 A 错误。多包引用相同的 HAR 时,会造成多包间代码和资源的重复拷贝,导致应用包变大,选项 B 正确。HAR 跨应用可用,HSP 仅限应用内或集成态可用,选项 C 描述相反。HSP 开发时会同时生成 .hsp 和 .har 文件,后者作为接口文件供使用方引用,选项 D 错误。
习题 3(多选题)
题目:关于 HarmonyOS 应用的分层架构,以下说法正确的有(多选):
A. 产品定制层包含不同设备的个性化业务,编译成 Entry 类型 HAP 包
B. 基础特性层需要单独部署的,设计为 Feature 类型的 HAP 包
C. 公共能力层的基础特性层依赖的公共能力,编译成 HAR 包或 HSP 包
D. 实践中单 Entry HAP 包 + 多 HSP 包是最常见的组合
答案:A、B、C
解读:产品定制层包含不同设备的个性化业务,编译成不同设备 Entry 类型 HAP 包,选项 A 正确。基础特性层需要单独部署的,设计为 Feature 类型的 HAP 包,不需要单独部署的,设计为 HAR 包或 HSP 包,选项 B 正确。公共能力层包含基础特性层依赖的公共能力,编译成 HAR 包或 HSP 包,选项 C 正确。实践中,单 Entry HAP 包 + 多 HAR 包在比较常见,而非多 HSP 包,选项 D 错误。
习题 4(代码填空题)
题目:请补全以下 HAR 模块的 Index.ets 文件,使其导出 formatDate 工具函数和 Logger 类。
// library/Index.ets
// 在此处填写导出代码
______________
______________
答案:export { formatDate } from ‘./src/main/ets/utils/Formatter’; 和 export { default as Logger } from ‘./src/main/ets/utils/Logger’;
解读:HAR 模块的 Index.ets 是共享包导出声明的入口,使用 export … from ‘…’ 语法导出对外暴露的接口。使用方在 oh-package.json5 中配置依赖后,通过 import 引用 HAR 中的组件、方法或类。
习题 5(代码改错题)
题目:某开发者将全局配置管理器设计为 HAR 包,供多个 HAP 模块共享。在运行时发现每个 HAP 模块中的配置管理器实例互不相同,导致配置不同步。请指出问题并给出修正方案。
答案:问题在于跨 HAP 共享单例对象时,应使用 HSP 动态共享包而非 HAR 静态共享包。HAR 在每个引用它的 HAP 中都会生成独立的副本,导致多实例问题。修正方案是将全局配置管理器模块从 HAR 改为 HSP,确保进程内只存一份实例。
// 将模块类型从 Static Library 改为 Shared Library
// 在 HSP 模块的 Index.ets 中导出配置管理器
export { ConfigManager } from './src/main/ets/manager/ConfigManager'
解读:HAR 是静态共享包,编译时会被打包进每个引用它的 HAP 或 HSP 中,导致多副本存在。HSP 是动态共享包,在运行时复用,进程内只存一份。当需要跨 HAP 共享单例对象时,必须使用 HSP。
习题 6(简答题)
题目:简述 HAR 和 HSP 的核心区别,以及各自的适用场景。
答案:HAR 是静态共享包,编译方式为随使用方编译,多副本存在,运行方式为静态加载,跨应用可用。HSP 是动态共享包,独立编译,单副本运行,动态加载,仅限应用内或集成态可用。HAR 适用于通用的工具函数、UI 组件库、资源文件等不需要运行时共享单例的场景,可以上传至 ohpm 仓库供其他开发者使用。HSP 适用于需要跨 HAP 共享单例对象的场景,以及需要按需动态下载的功能模块(如将非核心功能编译为 HSP,首次安装不包含在主包中,减少安装包体积),还适用于多安装包需要资源共享的场景。
解读:选择 HAR 还是 HSP 取决于具体需求。如果只是简单的代码和资源复用,且不需要运行时共享状态,使用 HAR 更简单便捷。如果需要跨模块共享单例状态,或需要按需加载减少包体积,则应使用 HSP。需要注意的是,HSP 开发时会同时生成 .hsp 和 .har 文件,后者作为接口文件供使用方引用。
习题 7(简答题)
题目:简述 ArkUI 中 MVVM 模式的三层职责划分,以及 ViewModel 层应该放在哪一层。
答案:ArkUI 采取 MVVM = Model + View + ViewModel 模式。View 层是 @Component 装饰组件渲染的 UI,负责用户界面展示和交互。Model 层只表达业务数据和数据访问结果(如接口 DTO),不包含页面状态逻辑。ViewModel 层面向页面或业务场景,负责组装页面状态、调用 service/repository、暴露事件方法。ViewModel 一般放在 viewmodel 或 store 层,不放 model 层。状态管理模块起到的就是 ViewModel 的作用,将数据与视图绑定在一起,更新数据时直接更新视图。
解读:MVVM 模式的核心价值在于分离 UI 和业务逻辑。View 层只负责渲染和交互,不包含业务逻辑;ViewModel 层负责业务逻辑和状态管理;Model 层负责数据定义和访问。在 ArkUI 中,@State、@Prop、@Link 等状态管理装饰器承担了 ViewModel 的部分职责,开发者需要在实践中根据项目复杂度决定是否需要独立的 ViewModel 层。
七、本节知识点总结
三种包类型
HAP 是应用安装和运行的基本单元,分为 Entry(主模块)和 Feature(动态扩展)两种类型。HAR 是静态共享包,随使用方编译,多副本存在,跨应用可用。HSP 是动态共享包,独立编译,单副本运行,仅限应用内或集成态可用。
HAR 静态共享包
用于共享 ArkUI 组件、工具函数、资源文件等。通过 Static Library 模板创建,Build > Make Module 编译生成。不能独立安装运行,C++ 代码编译为 .so 文件放在 libs 目录下。建议开启混淆保护代码。
HSP 动态共享包
用于跨 HAP 共享单例对象、按需加载功能模块、减少公共资源重复打包。通过 Shared Library 模板创建,需 API 10 及以上 Stage 模型和模块化编译模式。分为应用内 HSP 和集成态 HSP。
分层架构
产品定制层负责不同设备的个性化业务,编译为 Entry 类型 HAP。基础特性层抽象应用基础特性,需单独部署的设计为 Feature 类型 HAP,不需要单独部署的设计为 HAR 或 HSP。公共能力层提供基础特性层依赖的公共能力。
MVVM 模式
View 层是 @Component 组件渲染的 UI,Model 层表达业务数据和数据访问结果,ViewModel 层面向页面或业务场景组装页面状态、调用 service/repository。状态管理模块起 ViewModel 的作用。
模块化拆分原则
高内聚低耦合,按功能拆分,按“UI 模块 + 服务模块”拆分。推荐“单 HAP + 多 HAR”架构,避免为了拆分而拆分。跨 HAP 共享单例需用 HSP,HAR 会导致多实例。
下节预告
第12课将进入 ArkUI 应用测试与调试的学习,涵盖单元测试、UI 测试、性能分析工具的使用,以及常见问题的排查方法。
更多推荐
所有评论(0)