OpenHarmony HAR 静态共享组件库模块化拆分(API Version23 + 企业级分包方案)
摘要
单 entry 模块存放全部页面、工具、组件会导致工程臃肿、编译缓慢、多人协作代码冲突、功能无法复用。HAR 静态共享库用于拆分独立业务模块、通用基础能力库,实现代码解耦、多工程复用、分层隔离。API Version23 重构 HAR 依赖导入、资源互通、跨模块类型导出、编译缓存机制,修复低版本 HAR 资源找不到、类型导入爆红、跨模块工具循环依赖、图片 rawfile 无法访问、多 HAR 编译冲突等兼容缺陷。旧项目升级 API23 后常出现:导入 HAR 组件提示不存在、模型 interface 跨模块无法识别、rawfile 图片加载空白、同时引入多个 HAR 编译报错。本文基于 DevEco Studio API23+,完整讲解 HAR 库创建、依赖配置、跨模块资源 / 工具 / 组件调用、循环依赖规避、多模块分层架构实战,封装基础通用能力 HAR、业务笔记模块 HAR 两套完整示例,输出分包分层规范、导出约束、编译优化方案,为大型鸿蒙项目模块化拆分提供标准化模板。
关键词
OpenHarmony;ArkTS;API Version23;HAR;静态共享库;模块化拆分;多模块工程;代码复用;分层架构
一、引言
1.1 HAR 分包开发背景
小型课程设计单 entry 模块可正常开发,但中大型项目、多人协作、多终端复用场景存在明显痛点:
- 所有代码堆在 entry,文件上千,打开工程卡顿、编译耗时久;
- 通用工具、自定义组件、数据模型无法给其他项目复用;
- 业务耦合严重,删除某一功能会牵连大量页面代码;
- 多人开发容易出现文件命名冲突、git 合并大量冲突;
- 功能无法独立版本管控,基础能力更新全项目重新编译。
HAR(Harmony Archive)静态共享库用于解决以上问题,特点:
- 静态编译打包,编译时合并至主模块,运行无性能损耗;
- 可拆分通用基础库、独立业务模块库;
- 支持导出 ets 工具、自定义组件、类型、常量、资源;
- 支持多个 HAR 互相依赖,主 entry 统一引入所有 HAR。
OpenHarmony API Version23 HAR 核心升级变更:
- 严格控制跨模块导出权限,未 export 的类 / 函数外部模块不可访问;
- 统一 rawfile、media 资源跨 HAR 访问路径规则,修复图片资源加载失败;
- 优化循环依赖检测,编译阶段直接抛出依赖环报错,便于定位;
- 完善类型导出传递,HAR 导出 interface 后 entry 可正常识别类型;
- 分模块编译缓存,修改单个 HAR 仅重新编译该模块,大幅提升编译速度;
- 区分 HAR 静态库与 HSP 动态共享库,简化小型项目分包成本。
大量旧项目升级后跨模块导入爆红、资源加载空白,根源是未规范导出、资源路径写法错误、存在循环依赖,因此掌握 HAR 分包是企业级大型项目必备架构能力。
1.2 开发环境与分层场景
开发工具:DevEco Studio 5.0+ 适配系统:OpenHarmony API23、HarmonyOS NEXT 模块类型:entry(主应用模块)、多个 har 静态库模块 分包示例:
- har_base:全局工具、权限、网络、文件、通知、动画公共底层能力
- har_note:笔记独立业务(页面、CRUD、列表组件、数据库模型) 测试场景:主 entry 导入 har_base 工具、entry 引入 har_note 页面、HAR 之间互相依赖、跨模块资源访问、类型共享
二、API23+ HAR 核心约束与基础配置
2.1 HAR 与 entry 核心区别
表格
| 模块 | 用途 | 能否独立运行 | 页面注册 | Ability |
|---|---|---|---|---|
| entry | 主应用入口 | 可独立安装运行 | module.json5 注册 pages | 可定义 EntryAbility |
| HAR 静态库 | 代码 / 资源共享分包 | 不可单独运行 | 禁止注册 pages | 不允许定义 Ability |
2.2 module.json5 HAR 基础模板(har_base 示例)
json
{
"module": {
"name": "har_base",
"type": "har",
"description": "全局基础工具库",
"deviceTypes": ["phone"],
"deliveryWithInstall": false,
"installationFree": false
}
}
2.3 主 entry 引入 HAR 依赖(entry module.json5)
json
"dependencies": [
{
"name": "har_base",
"version": "1.0.0",
"scope": "shared"
},
{
"name": "har_note",
"version": "1.0.0",
"scope": "shared"
}
]
2.4 跨模块导入路径规则
- 导入 HAR 内 ets 代码:
import xxx from '@ohos:模块名/相对路径' - HAR 内部互相导入:同标准相对路径
../ - HAR 资源访问:模块名、r ('har 模块名:rawfile/xxx')
2.5 API23 强制约束
- HAR 中所有需要外部访问的类、函数、interface、常量必须加 export,私有代码禁止导出;
- HAR 不能定义 UIAbility、不能在 module.json5 注册 pages 页面;页面只能存放于 entry;
- 禁止双向循环依赖(har_base 依赖 har_note 同时 har_note 依赖 har_base);
- 动态权限、数据库初始化上下文仅 entry 可提供,HAR 工具仅接收外部传入 context;
- HAR 不支持 AppStorage 全局初始化,全局状态统一在 entry EntryAbility 管理;
- 多个 HAR 同名资源会产生覆盖冲突,资源文件名增加模块前缀区分。
三、基础最简 HAR 导入示例
3.1 har_base 内通用工具 har_base/src/main/ets/utils/toast_util.ets
ets
import promptAction from '@ohos.promptAction'
// 必须export导出,entry才能导入使用
export function showToast(msg: string) {
promptAction.showToast({message: msg})
}
3.2 entry 页面跨模块导入 HAR 工具
ets
// 固定格式 @ohos:har模块名/文件相对路径
import { showToast } from '@ohos:har_base/utils/toast_util'
@Entry
@Component
struct Index {
build() {
Button("调用HAR封装Toast")
.onClick(()=> showToast("来自基础HAR库工具"))
}
}
3.3 HAR 共享数据模型 interface
har_base/src/main/ets/model/NoteModel.ets
ets
export interface NoteItem {
id: number
title: string
content: string
}
entry 页面使用:
ets
import { NoteItem } from '@ohos:har_base/model/NoteModel'
@State note: NoteItem = {id:1, title:"测试", content:"HAR共享实体"}
四、完整分层多模块实战架构(两套 HAR 分包完整代码)
整体工程目录结构
plaintext
项目根目录
├─ entry(主应用,页面、EntryAbility、路由跳转)
├─ har_base(基础底层HAR:工具、常量、类型、通用组件)
│ └─ src/main/ets
│ ├─ utils 网络/文件/权限/通知/动画全套工具
│ ├─ model 全局interface、常量Constant
│ └─ components 通用弹窗、加载组件
└─ har_note(笔记业务HAR:数据库操作、笔记专用组件、业务逻辑)
└─ src/main/ets
├─ model 笔记业务实体
├─ db 笔记RDB封装
└─ components 笔记条目ListItem组件
4.1 实战一:基础底层 HAR har_base 通用导出汇总
har_base/src/main/ets/model/Constant.ets(全局常量导出)
ets
export const STORAGE_KEY = {
IS_LOGIN: "isLogin",
DARK_MODE: "darkMode"
}
export const PAGE_ROUTE = {
INDEX: "pages/index/index",
NOTE_LIST: "pages/note/NoteList"
}
har_base/src/main/ets/components/LoadingDialog.ets(通用组件导出)
ets
@Component
export struct LoadingDialog {
build() {
Column() {
Text("加载中...")
}
.width(120)
.height(100)
.backgroundColor("#00000099")
.borderRadius(12)
}
}
har_base/src/main/ets/utils/permission_util.ets(权限工具单例导出)
ets
import accessToken from '@ohos.accessToken'
import common from '@ohos.app.ability.common'
import { showToast } from './toast_util'
class PermissionUtil {
private static ins: PermissionUtil
private ctx: common.UIAbilityContext | null = null
static getInstance() {
if(!PermissionUtil.ins) PermissionUtil.ins = new PermissionUtil()
return PermissionUtil.ins
}
setContext(ctx: common.UIAbilityContext) {
this.ctx = ctx
}
async requestCamera(): Promise<boolean> {
if(!this.ctx) return false
const status = accessToken.checkAccessTokenSync(this.ctx, "ohos.permission.CAMERA")
if(status === accessToken.GrantStatus.PERMISSION_GRANTED) return true
const res = await accessToken.requestPermissions(this.ctx, ["ohos.permission.CAMERA"])
if(res[0].grantStatus === accessToken.GrantStatus.PERMISSION_GRANTED) return true
showToast("未授予相机权限")
return false
}
}
export default PermissionUtil.getInstance()
4.2 实战二:业务 HAR har_note 笔记数据库与条目组件
har_note/src/main/ets/db/note_db.ets(依赖 har_base 工具)
ets
import relationalStore from '@ohos.data.relationalStore'
import common from '@ohos.app.ability.common'
import { showToast } from '@ohos:har_base/utils/toast_util'
import { NoteItem } from '@ohos:har_base/model/NoteModel'
class NoteDbUtil {
private static ins: NoteDbUtil
private store: relationalStore.RdbStore | null = null
private ctx: common.UIAbilityContext | null = null
static getInstance() {
if(!NoteDbUtil.ins) NoteDbUtil.ins = new NoteDbUtil()
return NoteDbUtil.ins
}
setContext(ctx: common.UIAbilityContext) {
this.ctx = ctx
}
async init() {
if(!this.ctx) return
const config: relationalStore.StoreConfig = {
name: "note_db",
securityLevel: relationalStore.SecurityLevel.S1
}
this.store = await relationalStore.getRdbStore(this.ctx, config)
await this.store.executeSql(`CREATE TABLE IF NOT EXISTS note(id INTEGER PRIMARY KEY AUTOINCREMENT,title TEXT,content TEXT)`)
}
async addNote(title:string, content:string): Promise<number> {
if(!this.store) return -1
const bucket = {title, content}
return await this.store.insert("note", bucket)
}
async queryList(page:number, size:number): NoteItem[] {
if(!this.store) return []
const pred = new relationalStore.RdbPredicates("note")
pred.offset(page*size).limit(size)
const rs = await this.store.query("note", ["id","title","content"], pred)
let list: NoteItem[] = []
while(rs.goToNextRow()){
list.push({
id: rs.getLong(0),
title: rs.getString(1),
content: rs.getString(2)
})
}
rs.close()
return list
}
}
export default NoteDbUtil.getInstance()
har_note/src/main/ets/components/NoteItemCard.ets(导出笔记条目组件)
ets
import { NoteItem } from '@ohos:har_base/model/NoteModel'
@Component
export struct NoteItemCard {
@Param data: NoteItem
@Param onDelete: () => void
build() {
Row() {
Column({space:4}).layoutWeight(1) {
Text(this.data.title).fontSize(17)
Text(this.data.content).fontColor("#666")
}
Button("删除").backgroundColor("#f56c6c")
.onClick(()=> this.onDelete())
}
.width("100%")
.padding(16)
.backgroundColor(Color.White)
.borderRadius(10)
}
}
4.3 实战三:entry 主页面调用两套 HAR 完整示例 pages/note/NoteList.ets
ets
// 导入基础HAR工具、常量、通用组件
import PermissionUtil from '@ohos:har_base/utils/permission_util'
import { LoadingDialog } from '@ohos:har_base/components/LoadingDialog'
import { PAGE_ROUTE } from '@ohos:har_base/model/Constant'
// 导入笔记业务HAR数据库、条目组件
import NoteDbUtil from '@ohos:har_note/db/note_db'
import { NoteItemCard } from '@ohos:har_note/components/NoteItemCard'
import { NoteItem } from '@ohos:har_base/model/NoteModel'
import RouterUtil from '../utils/router_util'
@Entry
@Component
struct NoteListPage {
@State list: NoteItem[] = []
ctrl: CustomDialogController | null = null
async aboutToAppear() {
// 给HAR工具传入页面上下文
const ctx = getContext(this)
PermissionUtil.setContext(ctx)
NoteDbUtil.setContext(ctx)
await NoteDbUtil.init()
await this.loadData()
}
async loadData() {
this.list = await NoteDbUtil.queryList(0,10)
}
async delItem(id: number) {
await NoteDbUtil.deleteNote(id)
await this.loadData()
}
build() {
Column({space:12}) {
Text("笔记管理(多HAR分包工程演示)").fontSize(22).padding(10)
List({space:10}).layoutWeight(1) {
ForEach(this.list, (item:NoteItem)=>{
ListItem() {
NoteItemCard({
data: item,
onDelete: ()=> this.delItem(item.id)
})
}
})
}
Button("返回首页").onClick(()=> RouterUtil.replace(PAGE_ROUTE.INDEX))
}
.width("100%")
.height("100%")
.backgroundColor("#F5F5F5")
}
async aboutToDisappear() {
await NoteDbUtil.closeDB()
}
}
五、API23+ HAR 模块化分层与编译优化规范
5.1 分包分层规范(单向依赖,杜绝循环)
- 底层 har_base:无任何其他 HAR 依赖,提供通用基础能力;
- 业务 HAR(har_note、har_user):仅允许依赖 har_base,业务 HAR 之间禁止互相依赖;
- entry 主模块:可依赖所有 HAR,页面、Ability、全局状态全部放在 entry;
- 分层依赖流向:entry → 业务 HAR → 底层 har_base,单向不回流。
5.2 导出编码规范
- 所有对外可访问函数、类、组件、interface 必须添加 export;
- 仅暴露外部需要调用的 API,内部辅助工具私有不导出;
- 单例工具使用
export default,常量 / 类型使用命名export const/interface; - HAR 内组件统一 @Component + export,entry 才能直接引入渲染。
5.3 资源访问规范
- HAR 图片资源:
$r('har模块名:media/图片名'); - HAR rawfile 静态 HTML:
$r('har模块名:rawfile/index.html'); - 不同 HAR 资源文件名增加模块前缀,避免同名覆盖;
- 通用全局图片统一存放 har_base media 目录,业务图片存放对应业务 HAR。
5.4 编译性能优化规范
- 按功能拆分多个小型 HAR,不创建单个超大 HAR;
- 修改仅涉及单一 HAR 时,仅该模块增量编译,缩短等待时间;
- 稳定不变的底层基础能力抽离为独立 HAR,极少重新编译;
- 调试阶段可临时移除未开发完成的 HAR 依赖,加快编译速度。
5.5 协作开发规范
- 不同开发人员负责独立 HAR 模块,代码隔离减少冲突;
- HAR 对外 API 统一维护导出文件,接口变更统一同步;
- 公共基础修改统一提交 har_base,各业务模块同步更新依赖。
六、API23 升级高频 HAR 兼容问题与解决方案
问题 1:entry 导入 HAR 代码提示爆红,找不到模块 解决:entry module.json5 添加对应 dependencies 依赖,导入路径使用@ohos:har名/标准前缀。
问题 2:HAR 内定义 interface,entry 接收时报类型不匹配 解决:实体 interface 统一放在底层 har_base 并 export 导出,业务 HAR、entry 统一从 base 导入。
问题 3:HAR 中读取 media 图片空白无法显示 解决:使用跨模块资源格式$r('har模块名:media/xxx'),不使用本地相对资源写法。
问题 4:编译提示循环依赖报错 cyclic dependency 解决:调整分层,业务 HAR 只依赖底层 base,业务 HAR 之间不互相导入。
问题 5:HAR 中调用 RDB/Preferences 提示上下文为空 解决:HAR 工具仅提供方法,由 entry 页面获取 context 传入 HAR 工具 setContext。
问题 6:多个 HAR 存在同名组件,渲染出现错乱 解决:组件、资源文件名增加 HAR 模块专属前缀,避免命名冲突。
七、总结
HAR 静态共享库是 OpenHarmony 大型项目标准化分包方案,API Version23 完善跨模块导出、资源访问、循环依赖检测、增量编译机制,解决单 entry 工程臃肿、代码无法复用、编译缓慢、多人协作冲突等核心痛点。 标准分层架构:底层基础 HAR 存放全局通用工具与基础组件,各业务独立拆分为业务 HAR,主 entry 仅负责页面与应用生命周期管理,严格单向依赖杜绝循环耦合。全部代码兼容 API23 与 HarmonyOS NEXT,适合课程设计大型综合项目、企业商用鸿蒙工程模块化改造。
更多推荐



所有评论(0)