鸿蒙 PC 三方库适配 HNP 打包流程的”入场券”hnp.json 文件解读
hnp.json虽然只有几行JSON,但它是鸿蒙原生包打包流程的“入场券”。type声明文件类型,name必须与HPKBUILD和README.OpenSource保持一致,version是HNP包自身的发布版本而非上游版本。理解了它,就理解了OpenHarmony原生包打包的入口逻辑。

鸿蒙 PC 三方库适配 HNP 打包流程的”入场券”hnp.json 文件解读
项目路径[1]
前言
如果你刚接触 OpenHarmony 的三方库适配,可能会觉得 hnp.json 这个文件看起来太简单了——只有区区几行 JSON,甚至 install 还是个空对象。它真的有那么重要吗?
答案是:非常重要。hnp.json 虽然小,但它是整个 HNP 打包流程的”入场券”。没有它,打包工具根本不认识你的库;有了它,才能把编译产物变成 OpenHarmony 设备上可安装的原生包。
这篇文章就用通俗的方式,把 hnp.json 的每个字段、它在构建流程中的位置、以及实际使用中的注意事项讲清楚。
先看文件长什么样
SHA 库的 hnp.json 内容如下:
{
“type”: “hnp-config”,
“name”: “sha”,
“version”: “1.1.0”,
“install”: {
}
}
就这 5 行有效内容。但每一行都有它的作用,下面逐个拆解。
逐字段解读
1. type — “我是谁”
“type”: “hnp-config”
通俗理解:这个字段就像身份证上的”证件类型”,告诉读取这个文件的程序:”我是一个 HNP 配置文件,不是别的什么东西。”
技术细节:
- 固定值,必须是 “hnp-config”
- HNP 打包工具(hnpcli)在打包时,首先检查这个字段
- 如果 type 不是 “hnp-config”,打包工具会拒绝处理,直接报错
类比:就像 XML 文件头部的 <?xml version=”1.0″?> 声明,或者 HTML 的 <!DOCTYPE html>,是一种”自我声明”机制。
2. name — “我叫什么”
“name”: “sha”
通俗理解:包的名字。就像你安装 App 时看到的包名,比如微信叫 com.tencent.mm,这里 SHA 库就叫 sha。
技术细节:
- 必须与 HPKBUILD 中的 pkgname 保持一致
- 也必须与 README.OpenSource 中的 Name 保持一致
- 打包后生成的 HNP 包文件名就是 sha.hnp
一致性对照:

三个文件中的名称必须统一,否则构建系统会混乱——想象一下,如果身份证、户口本、护照上的名字不一样,办事时会有多麻烦。
3. version — “我几岁了”
“version”: “1.1.0”
通俗理解:HNP 包的版本号。就像手机 App 的版本号(比如微信 8.0.33),用来区分同一个包的不同版本。
技术细节:
- 采用语义化版本号格式:主版本.次版本.修订号(Major.Minor.Patch)
- 这里的 1.1.0 是 HNP 包自身的版本,不是上游 SHA 库的版本
一个容易混淆的点:
很多人会问:为什么 version 是 1.1.0,而 HPKBUILD 里的 pkgver 是一长串 commit hash 3ee0d88fc4f629b2e084f1b4cbf22cd3597542fb?
它们是两个不同的版本概念:

打个比方:pkgver 是”原材料批次号”(你用了哪一批源码),version 是”产品型号”(你发布的包是第几版)。同一批原材料可以生产多个产品版本(比如修复了适配 bug,重新打包),同一个产品版本也可能换过原材料(比如升级了上游版本但接口没变)。
4. install — “安装后要做什么”
“install”: {}
通俗理解:安装后的额外操作配置。目前是空对象 {},意思是”安装完就完事了,不需要额外操作”。
技术细节:
- 类型是 JSON 对象
- 空对象 {} 表示无需额外安装步骤
- 如果需要,可以配置安装后的脚本执行、环境变量设置等
什么时候需要填写 install?
大多数简单的库都不需要,{} 就够了。但在以下场景可能需要:
- 需要注册系统服务:安装后要注册一个守护进程
- 需要设置环境变量:安装后要往系统 PATH 里加路径
- 需要执行初始化脚本:安装后要跑一段配置脚本
- 需要创建符号链接:安装后要建立特定的链接关系
假设的复杂 install 示例(仅作说明,SHA 库不需要):
“install”: {
“post-install”: “scripts/setup.sh”,
“env”: {
“SHA_HOME”: “${install_dir}”
}
}
对于 SHA 这种纯算法库,安装就是把头文件和库文件放到正确位置,不需要额外操作,所以 {} 完全合理。
hnp.json 在构建流程中的位置
光看文件本身可能觉得简单,但把它放到整个构建流程中,就能理解它的关键作用了。
构建流程全景
源码下载(git clone)
│
▼
应用补丁(patch)
│
▼
编译构建(cmake + make)
│
▼
安装产物(make install) ← 产物放到 usr/sha/arm64-v8a/ 等目录
│
▼
┌─────────────────────────────────────────────┐
│ 打包阶段(archive 函数) │
│ │
│ ① 打 tar.gz 包 │
│ ② 复制 hnp.json 到产物目录 ← 关键步骤! │
│ ③ 设置架构环境变量 │
│ ④ 执行 hnpcli pack 打 HNP 包 │
│ ⑤ 清理环境变量 │
└─────────────────────────────────────────────┘
│
▼
生成最终产物:sha.hnp + sha_xxx.tar.gz
HPKBUILD 中的关键代码
在 HPKBUILD 的 archive() 函数中,有这样一行:
cp hnp.json $LYCIUM_ROOT/usr/$pkgname/$ARCH
这行代码做的事情很简单:把 hnp.json 复制到编译产物目录中。
为什么要这么做?因为 hnpcli pack 打包工具在生成 HNP 包时,需要从产物目录中读取 hnp.json 来识别包的元数据。没有这个文件,打包工具不知道这是什么东西,自然无法生成 .hnp 包。
打包命令
${HNP_TOOL} pack -i ${LYCIUM_ROOT}/usr/$pkgname/$ARCH -o ${LYCIUM_ROOT}/output/$ARCH/
- -i:输入目录,即包含 hnp.json 和编译产物的目录
- -o:输出目录,生成的 .hnp 包放在这里
hnpcli 会在输入目录中寻找 hnp.json,读取其中的 name、version 等信息,然后把整个目录打包成 sha.hnp。
hnp.json 的文件分布
在 SHA 库的适配中,hnp.json 出现在多个位置:
lycium_plusplus/thirdparty/sha/
├── hnp.json ← 源文件(手写)
├── HPKBUILD
├── HPKCHECK
└── output/
└── usr/
└── sha/
├── arm64-v8a/
│ └── hnp.json ← 复制来的(构建时自动复制)
└── armeabi-v7a/
└── hnp.json ← 复制来的(构建时自动复制)
- **根目录的 hnp.json**:这是开发者手写的源文件,是“原件”
- **产物目录中的 hnp.json**:构建时由 cp hnp.json … 命令复制过去,是“复印件”
两个架构(arm64-v8a 和 armeabi-v7a)的 hnp.json 内容完全相同,因为包的元数据不随架构变化。
HNP 包是什么?
理解 hnp.json 的意义,需要先理解 HNP 包是什么。
类比理解

HNP(Harmony Native Package)是 OpenHarmony 的原生库包格式,专门用于分发 C/C++ 原生库。它把头文件、库文件、可执行文件等打包在一起,方便在 OpenHarmony 设备上安装和使用。
HNP 包 vs tar.gz 包
SHA 库的构建会同时生成两种包:

hnp.json 只对 HNP 包有意义,tar.gz 包不需要它。
HNP 包的内部结构
一个 HNP 包本质上是一个包含特定目录结构的压缩包:
sha.hnp
├── hnp.json ← 包的”身份证”
├── bin/ ← 可执行文件
│ ├── hmac
│ ├── pwd2key
│ ├── sha256sum
│ └── sha_test
├── include/ ← 头文件
│ └── sha/
│ ├── sha1.h
│ ├── sha2.h
│ ├── hmac.h
│ └── …
└── lib/ ← 库文件
├── libsha.so
├── libsha_static.a
└── cmake/
└── sha/
hnp.json 就放在包的根目录,是整个包的入口文件。
常见问题
Q1:hnp.json 可以省略吗?
不可以。 如果没有 hnp.json,hnpcli pack 命令会报错,无法生成 HNP 包。它是打包的必要条件。
Q2:type 字段可以改成别的值吗?
不可以。type 必须是 “hnp-config”,这是打包工具识别配置文件的固定标识。改成别的值会导致打包失败。
Q3:name 可以和 pkgname 不一样吗?
强烈不建议。 虽然技术上可能不会直接报错,但名称不一致会导致:
- 包管理混乱,无法通过名称找到对应的包
- 依赖解析出错
- 用户使用时产生困惑
Q4:version 为什么要和上游版本分开?
因为它们描述的是不同的事情:
- 上游版本(commit hash):描述“用了什么源码”
- HNP 版本(1.1.0):描述“发布了什么包”
实际场景:你可能用同一份源码发布了两次包(第一次有 bug,修复后重新打包),这时上游版本没变,但 HNP 版本应该从 1.1.0 升到 1.1.1。
Q5:install 什么时候需要填写?
对于大多数纯库(如 SHA、加密算法库、数学库等),{} 就够了。只有需要安装后执行额外操作的场景才需要填写,比如:
- 需要注册系统服务
- 需要修改系统配置
- 需要设置环境变量
Q6:修改 hnp.json 后需要重新构建吗?
需要。hnp.json 是在 archive() 阶段被复制到产物目录并参与打包的。修改后需要重新执行打包步骤,新的 hnp.json 才会生效。
如果只是修改了 hnp.json(没改源码),可以只重新执行 archive 步骤,不需要重新编译。
实践建议
1. 保持三个文件名称一致
hnp.json
→ “name”: “sha”HPKBUILD
→ pkgname=shaREADME.OpenSource
→ “Name”: “sha”
2. 版本号要有意义
HNP 版本号建议遵循语义化版本规范:

3. 不要手动修改产物目录中的 hnp.json
产物目录中的 hnp.json 是自动复制的,手动修改会在下次构建时被覆盖。只修改根目录的源文件。
4. 将 hnp.json 纳入版本控制
hnp.json 是项目配置的一部分,应该和 HPKBUILD、HPKCHECK 一起纳入 Git 版本控制。
总结
hnp.json 虽然只有几行,但它是 HNP 打包流程的关键配置文件:

核心要点:
- hnp.json 是生成 HNP 包的必要条件,没有它就无法打包
- name 必须与 HPKBUILD 和 README.OpenSource 中的名称保持一致
- version 是 HNP 包自身的版本,与上游源码版本是两个概念
- install 大多数情况下为空 {},只有特殊需求才需要填写
- 它在构建的 archive() 阶段被复制到产物目录,供 hnpcli pack 读取
一个小文件,一个大门道。理解了 hnp.json,就理解了 OpenHarmony 原生包打包的入口逻辑。
本文由人人都是产品经理作者【null】,微信公众号:【nutpi】,原创/授权 发布于人人都是产品经理,未经许可,禁止转载。
题图来自Unsplash,基于 CC0 协议。
- 目前还没评论,等你发挥!

起点课堂会员权益



