鸿蒙项目里 oh-package.json5 的角色类似于前端的 package.json,但它分成了工程级和模块级两份文件,各自承担不同的职责。这篇文章基于 OHPM 5.0+ 的实际项目配置,把每个字段的设计意图和使用场景讲清楚。
一、工程级与模块级的区别
从 OHPM 5.0.0 开始,oh-package.json5 被拆成两级。工程级文件位于项目根目录,模块级文件位于每个模块(entry、library、feature 等)的根目录下。
工程级文件负责全局配置:modelVersion、overrides、overrideDependencyMap、parameterFile、hooks。它不建议放 dependencies 和 dynamicDependencies,因为具体的编译依赖应该由各模块自行声明。
模块级文件负责描述一个可发布的包:name、version、main、types、license、dependencies、devDependencies、dynamicDependencies 等。
拿 ohrouter 项目的工程级配置举例:
{
"modelVersion": "5.0.0",
"description": "HMRouter Project",
"dependencies": {},
"devDependencies": {
"@ohos/hypium": "1.0.19",
"@ohos/hamock": "1.0.0"
},
"overrides": {
"@hadss/hmrouter": "file:./HMRouterLibrary"
},
"parameterFile": "./dependencies.json5",
"hooks": {
"postInstall": "node ./scripts/post-install.mjs"
}
}
这个配置里 dependencies 是空的,所有生产依赖都由各模块自己声明。工程级只保留了 devDependencies(测试框架)、overrides(本地覆盖)和 hooks(安装后钩子)。
再看 PullToRefresh 的工程级配置,它的 dependencies 里放了 @ohos/lottie,这其实不太规范。更好的做法是把 lottie 的依赖声明放到实际 import 它的模块里。

二、模块级必填字段
对一个要发布到 ohpm 中心仓的模块来说,必填字段有:name、version、main、license。
{
"name": "@hadss/hmrouter",
"version": "1.0.0",
"main": "Index.ets",
"license": "Apache-2.0"
}
name 的命名规则比较严格:@group/packagename 格式,group 只能小写字母开头,packagename 不能以点、中划线、下划线结尾,不能是 ArkTS 的保留关键字。在同一个应用工程内,不同模块的 name 不能重复。
version 必须遵循 semver 规范,从 1.0.0 开始。main 指向模块的入口文件,通常是 Index.ets。license 遵循 SPDX 标准,常见的有 Apache-2.0、MIT、ISC。
看看 ImageKnife library 模块的实际配置:
{
"name": "@ohos/imageknife",
"version": "3.2.9-rc.0",
"main": "index.ets",
"license": "Apache License 2.0",
"description": "专门为OpenHarmony打造的一款图像加载缓存库,致力于更高效、更轻便、更简单",
"types": "",
"keywords": ["OpenHarmony", "ImageKnife", "glide", "HarmonyOS"],
"author": "ohos_tpc",
"repository": "https://gitcode.com/openharmony-tpc/ImageKnife",
"dependencies": {
"@ohos/gpu_transform": "^1.0.2"
}
}
types 字段用于指定类型声明文件(.d.ts/.d.ets),闭源发布时 ohpm 会校验 types 路径下的声明文件是否实际存在。keywords 和 description 有助于在中心仓里被搜索到。
三、三种依赖类型
dependencies、devDependencies、dynamicDependencies 各有适用场景。
dependencies 是生产依赖,即代码里 import 了且运行时需要的库。比如 imageknifepro 的 library 模块依赖了自己编译出来的 so 文件:
{
"dependencies": {
"libimageknifepro.so": "file:./src/main/cpp/types/libentry"
}
}
devDependencies 是开发态依赖,仅在开发和测试时使用,不会打包到最终的 HAP/HSP 中。典型代表是测试框架 @ohos/hypium 和 mock 库 @ohos/hamock。
dynamicDependencies 用于动态加载 HSP 的场景。配合 ArkTS 的 dynamic import 语法,动态依赖不会在加载时被编译,而是按需导入,启动速度更快。
一个容易踩的坑:工程级 oh-package.json5 里不建议配 dependencies 和 dynamicDependencies。如果一个 HAR 模块要发布,它的所有直接依赖必须在自己的 oh-package.json5 里声明完整,不能依赖工程级的配置来"补漏"。ohpm publish 时会校验包内 oh-package.json5 的依赖完整性。
四、依赖版本语法
ohpm 的版本语法和 npm 基本一致,支持以下几种写法:
{
"dependencies": {
// 精确版本
"lib_exact": "1.0.0",
// ^ 前缀:锁定主版本号,允许 minor 和 patch 更新
// ^1.0.1 匹配 >=1.0.1 <2.0.0
"lib_caret": "^1.0.1",
// ~ 前缀:锁定主版本号和次版本号,只允许 patch 更新
// ~1.0.1 匹配 >=1.0.1 <1.1.0
"lib_tilde": "~1.0.1",
// tag 标签引入
"lib_tag": "tag:beta",
// 本地 HAR 文件
"lib_local_har": "file:./libs/xxx.har",
// 本地源码目录
"lib_local_src": "file:../module1"
}
}
范围版本有个细节:它优先选取正式版本,只有没有匹配的正式版本时才会选先行版本(如 rc、beta)。ImageKnife 的 "@ohos/gpu_transform": "^1.0.2" 就是一个典型的 caret 范围依赖。
本地文件引入(file: 前缀)有两种用途。引用本地 HAR/tgz 文件时,路径指向文件。引用本地源码时,路径指向模块目录,ohpm install 会创建软链接指向该目录。

五、overrides 本地覆盖
overrides 是工程级的配置,用于把依赖树中某个包替换为指定版本。它只能配在工程根目录的 oh-package.json5 里,模块级配置无效。
ohrouter 项目的用法最为典型:
{
"overrides": {
"@hadss/hmrouter": "file:./HMRouterLibrary"
}
}
这行配置的意思是:不管依赖树中哪个模块引用了 @hadss/hmrouter(比如 hsp_cases、har_cases 等 feature 模块都在 dependencies 里声明了这个包),实际安装时都用本地的 HMRouterLibrary 源码目录替代。
这在库开发阶段非常实用。你在开发 HMRouterLibrary 的同时需要在 Example 应用里调试,如果每次改代码都要先 publish 再 install,效率太低。用 overrides 指向本地源码,ohpm install 之后各模块引用的都是同一份源码,改完立刻生效。
overrides 还支持指定具体版本号和模糊版本:
{
"overrides": {
"foo": "1.0.0",
"bar": "file:./libs/bar.har"
}
}
六、hooks 钩子
hooks 支持 8 种事件:preInstall、postInstall、preUninstall、postUninstall、preVersion、postVersion、prePublish、postPublish。
ohrouter 用了 postInstall 钩子:
{
"hooks": {
"postInstall": "node ./scripts/post-install.mjs"
}
}
每次执行 ohpm install 之后,会自动运行 post-install.mjs 脚本。这种模式常用于依赖安装后需要做额外处理的场景,比如复制文件、生成配置、校验环境等。
需要注意:hooks 只执行当前工程中的脚本,不会执行依赖包里的 hooks。这是出于安全考虑,防止安装第三方库时被执行任意代码。
七、parameterFile 参数化配置
parameterFile 解决的是多模块版本统一管理的问题。当一个仓库有多个 HAR/HSP 模块要发布,手动逐个改版本号非常繁琐。
ohrouter 的 HMRouterLibrary 模块就用了参数化:
// HMRouterLibrary/oh-package.json5
{
"name": "@hadss/hmrouter",
"version": "@param:version",
"main": "Index.ets",
"license": "Apache-2.0"
}
version 字段的值是 @param:version,它会在构建时被替换为 parameterFile 配置文件中 version 键对应的实际版本号。
工程级 oh-package.json5 里需要声明 parameterFile 路径:
{
"parameterFile": "./dependencies.json5"
}
parameterFile 指向的 json5 文件内容格式如下:
{
"version": "1.2.3"
}
这样发版时只需要改一个文件,所有模块的版本号就自动同步了。parameterFile 支持参数化的字段有 version、dependencies、devDependencies 和 dynamicDependencies。

八、modelVersion 的含义
modelVersion 出现在工程级 oh-package.json5 里,标识开发态版本号。它和 OHPM 客户端版本相关,不同的 modelVersion 对应不同的功能支持。
// PullToRefresh 工程级
{ "modelVersion": "5.0.0" }
// ImageKnife 工程级
{ "modelVersion": "5.0.1" }
5.0.0 表示工程创建时使用的是 OHPM 5.0.0 版本的配置格式。5.0.1 支持的功能略多。当 DevEco Studio 升级或 OHPM 升级后,IDE 可能会提示你更新 modelVersion。
一般情况下不需要手动改这个字段,让 IDE 自动管理即可。但如果你从低版本工程迁移过来,或者从别人那里拷贝了工程配置,需要确认 modelVersion 和当前开发环境的 OHPM 版本兼容。
九、packageType 字段
在 HSP(Shared Library)模块的 oh-package.json5 里会出现 packageType 字段:
{
"name": "@ohos/libraryimageknife",
"version": "1.0.0",
"main": "Index.ets",
"license": "Apache-2.0",
"packageType": "InterfaceHar",
"dependencies": {
"@ohos/imageknife": "file:../library"
}
}
packageType 为 InterfaceHar 时标识这是一个 HSP 包。新建 Shared Library 模块时 IDE 会自动生成这个字段。普通 HAR(Static Library)模块没有这个字段。如果你要把一个 HAR 改成 HSP,除了修改 module.json5 中的 type,还需要在 oh-package.json5 里加上 packageType。
十、兼容性检测字段
发布到 ohpm 中心仓的包还有一组由构建工具自动填充的兼容性字段:compatibleSdkVersion、compatibleSdkType、obfuscated、nativeComponents。
这些字段在 hvigor 构建时自动写入,不需要手动维护。它们的作用是让消费方的 SDK 能做兼容性检测——比如一个用 API 12 编译的三方库,被一个 API 11 的项目引用时,SDK 能给出兼容性警告。
ohpm publish 和 prepublish 命令会检测这些字段是否存在。.ohpmrc 中的 compability_log_level 配置控制缺失时是警告还是报错。
以上就是本篇内容的所有了~有什么问题欢迎在评论区提出