Capacitor 应用鸿蒙化实战:用 hionic 把 React 应用跑在 OpenHarmony 上
Capacitor 应用鸿蒙化实战:用 hionic 把 React 应用跑在 OpenHarmony 上
本文记录了使用CPF-Ionic 团队开源的 hionic 命令行工具,从一个 Vite + React Web 项目出发,初始化 Capacitor 工程、添加 OpenHarmony 平台、解决 openssl 原生依赖、构建签名 HAP 的完整过程。
包含 Capacitor 框架介绍、hionic 与 capacitor-cli / openharmony-capacitor 的架构关系、逐步操作记录、两轮编译报错的根因分析与修复,以及踩坑复盘。所有步骤均在本机(macOS arm64 + DevEco Studio)实际执行验证。
一、背景
1.1 Capacitor 简介
Capacitor 是 Ionic 团队推出的新一代混合应用框架,可以理解为 “现代版 Cordova”:
| 维度 | Cordova | Capacitor |
|---|---|---|
| Web 资源承载 | 运行时由 WebView 加载 www/,桥接走 cordova.exec 消息队列 | Web 产物直接打包进原生工程 rawfile,桥接更薄 |
| 工程结构 | CLI 生成平台工程后由 CLI 维护 | 平台工程提交进版本库,开发者直接拥有原生工程 |
| 前端集成 | 需 cordova 项目结构 | 任意前端项目(Vite/webpack/Next.js)npx cap init 即可接入 |
| 插件 API | navigator.* / cordova.exec | 现代 Promise API(@capacitor/camera 等),兼容 Cordova 插件 |
| 版本 | cordova 13.x | capacitor 8.x(本文实测 8.5.2) |
Capacitor 的核心工作流是四步循环:
前端开发(Vite/React/Vue...)
→ build (vite build 产出 dist/)
→ sync (把 dist/ 拷贝进原生工程 rawfile,同步插件注册)
→ open/run(打开 IDE 或运行到设备)
1.2 hionic:华为的 Capacitor 鸿蒙化 CLI
华为 CPF-Ionic 团队对 Capacitor 做了完整鸿蒙化,由三个部分组成(已同步到 AtomGit,组织主页 https://atomgit.com/cpf-ionic ):
| 组件 | 仓库 | 角色 |
|---|---|---|
| hionic(npm) | CPF-Ionic/capacitor-cli | 命令行工具(npm 包名 hionic,实测版本 2.1.16) |
| OHOS 平台运行时 | CPF-Ionic/openHarmony-capacitor(npm 包 @capacitor-ohos/ohos,实测 8.0.2) | ArkTS + C++ 实现的鸿蒙 Capacitor 运行时(HAR 源码分发) |
| 插件生态 | CPF-Ionic 组织(capacitor-geolocation、capacitor-haptics、capacitor-clipboard、ionic-native-* 等 30+ 仓库) | Capacitor 官方插件的 OHOS 实现 |
hionic 的命令设计与 Capacitor 原生 CLI 对齐,并扩展了鸿蒙平台:
hionic start <Cordova|Capacitor> <path> [id] [name] [template] # 创建 Web 项目(react/vanilla 模板)
hionic init [name] [id] # 把已有 Web 项目初始化为 Capacitor 工程
hionic add openharmony # 添加鸿蒙平台
hionic buildui # 构建前端产物
hionic sync openharmony # 同步 Web 产物 + 插件到鸿蒙工程
hionic buildapp openharmony # 构建应用(实际引导 hvigorw)
hionic run / open <platform> # 运行 / 用 IDE 打开
1.3 实验目标
| 维度 | 要求 |
|---|---|
| 前端技术栈 | Vite + React(--template=react),前端代码零改动 |
| 平台 | openharmony(鸿蒙壳工程,DevEco 可直接打开) |
| 构建产物 | 签名 HAP,可安装到模拟器运行 |
二、环境
| 依赖 | 版本 | 说明 |
|---|---|---|
| macOS | arm64 (Apple Silicon) | |
| Node.js | v26.0.0 | |
| hionic | 2.1.16 | npm install -g hionic |
| @capacitor/core / cli | 8.5.2 / 项目内 | hionic 的 init 依赖它们(见踩坑 1) |
| @capacitor-ohos/ohos | 8.0.2 | 鸿蒙运行时,add openharmony 时从 node_modules 拷入工程 |
| DevEco Studio | 内置 hvigor / ohpm / SDK 5.0.5(17) | |
| 设备 | 模拟器 7.0.0.106(SP1DEVC00E999R4P11),hdc list targets → 127.0.0.1:5555 |
三、逐步操作过程
第 1 步:创建项目
hionic start capacitor capacitorMyApp com.nutpi.MyApp capacitorMyHarmonyApp react
这条命令实际执行了三件事:
npm create vite capacitorMyApp -- --template react— 生成 Vite + React 工程;npm install— 安装 143 个前端依赖(React 19.2.6);npx cap init capacitorMyHarmonyApp com.nutpi.MyApp— 初始化 Capacitor 配置。
结果:前两步成功,第三步失败(踩坑 1),手动修复后 capacitor.config.json 生成:
{
"appId": "com.nutpi.MyApp",
"appName": "capacitorMyHarmonyApp",
"webDir": "www"
}
注意
webDir默认是www,而 Vite 产物目录是dist,后面 sync 前必须改掉(踩坑 3)。
第 2 步:添加鸿蒙平台
hionic add openharmony
执行过程:
- 从
hionic/templates/capacitor拷贝鸿蒙壳工程模板到openharmony/; - 把
node_modules/@capacitor-ohos/ohos运行时源码拷入openharmony/capacitor/(ArkTS HAR 源码,非预编译 so); - 渲染 48 个模板文件:
AppScope/app.json5写入 bundleNamecom.nutpi.MyApp、应用名capacitorMyHarmonyApp、版本 1.0.0 等。
生成结构:
capacitorMyApp/
├── openharmony/ # 鸿蒙壳工程(DevEco 可直接打开)
│ ├── AppScope/app.json5 # bundleName: com.nutpi.MyApp
│ ├── entry/ # 主模块(EntryAbility + Capacitor 容器)
│ ├── capacitor/ # @capacitor-ohos/ohos 运行时(ArkTS + C++ HAR)
│ │ └── src/main/cpp/ # 桥接层 C++ 源码(CMakeLists.txt 编译)
│ ├── build-profile.json5 # targetSdk 5.0.5(17) / compatible 5.0.0(12)
│ └── oh-package.json5
├── src/ # React 源码(零改动)
└── capacitor.config.json
第 3 步:构建前端 + 同步
hionic buildui # 实际执行 vite build,产出 dist/(222KB JS)
修改 capacitor.config.json 的 webDir 为 dist(踩坑 3),然后:
hionic sync openharmony
# Resolved webDir: dist -> .../capacitorMyApp/dist
# Doing copy openharmony platform success
# Doing sync 0 Capacitor plugins
sync 后验证:openharmony/entry/src/main/resources/rawfile/www/ 下出现了 React 产物(index.html、assets/index-YeS5K1AL.js…)以及 capacitor.js、native-bridge.js 桥接脚本——Web 层与原生层的对接点。
第 4 步:构建 HAP(两轮报错与修复)
第一轮报错:libssl.so.3 missing
用 hvigorw 构建:
cd openharmony
export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk
export PATH=".../tools/hvigor/bin:.../tools/node/bin:.../tools/ohpm/bin:$PATH"
hvigorw assembleHap --mode module -p module=entry@default -p product=default -p requiredDeviceType=phone
报错:
ninja: error: '.../openharmony/capacitor/libs/x86_64/libssl.so.3',
needed by '.../obj/x86_64/libcapacitor.so', missing and no known rule to make it
根因:查看 capacitor/src/main/cpp/CMakeLists.txt:
set(OPENSSL_LIB_PATH ${NATIVERENDER_ROOT_PATH}/../../../libs/${OHOS_ARCH})
target_link_libraries(capacitor PUBLIC
${OPENSSL_LIB_PATH}/libssl.so.3
${OPENSSL_LIB_PATH}/libcrypto.so.3)
target_include_directories(capacitor PUBLIC
${NATIVERENDER_ROOT_PATH}/openssl/${OHOS_ARCH}/include)
@capacitor-ohos/ohos 8.0.2 的原生层(自研 Socket/SSLSocket 网络栈)链接 openssl 3.x,需要两组材料:
| 材料 | 路径 | 状态 |
|---|---|---|
| 编译好的 so/a 库 | capacitor/libs/<abi>/(libssl.so.3、libcrypto.so.3 等) | ❌ 缺失 |
| openssl 头文件 | capacitor/src/main/cpp/openssl/<abi>/include/(142 个头文件) | ❌ 缺失 |
其 README 明确写着:“本工程依赖 openssl…编译之前先集成 openssl,只有成功集成后,才可编译”,官方集成方法是 li_in/openharmony-capacitor-openssl3.5 手动编译。而 hionic 的 add openharmony 完全没有 hcordova 那样的 openssl 自动安装逻辑(全局搜索 hionic 源码无任何 openssl 处理)——这是 hionic 与 hcordova 的一个显著功能差距。
修复:恰好此前在同一台机器上用 hcordova 创建过项目,hcordova 的 platform add ohos 曾自动克隆并编译过 openssl 3.x(同属 CPF 生态,ABI 与工具链一致),直接复用:
# 1. 拷贝预编译库(x86_64 模拟器 + arm64-v8a 真机)
SRC=MyApp/harmonyos/cordova/libs
DST=capacitorMyApp/openharmony/capacitor/libs
cp -R $SRC/x86_64 $DST/x86_64 # libssl.so.3 / libcrypto.so.3 / libssl.a / engines-3 / ossl-modules
cp -R $SRC/arm64-v8a $DST/arm64-v8a
# 2. 拷贝 openssl 头文件
SRC2=MyApp/harmonyos/cordova/src/main/cpp/openssl
DST2=capacitorMyApp/openharmony/capacitor/src/main/cpp/openssl
cp -R $SRC2/x86_64 $DST2/x86_64 # include/ 下 142 个头文件
cp -R $SRC2/arm64-v8a $DST2/arm64-v8a
第二轮报错:openssl/ssl.h not found
第一处修完(ninja 能找到 libssl.so.3 了),重新构建,编译器报:
SSLSocket.h:21:10: fatal error: 'openssl/ssl.h' file not found
HttpUrl.cpp:18:10: fatal error: 'openssl/md5.h' file not found
根因:CMake 的 include 路径 cpp/openssl/<abi>/include 为空——修复第一轮时只拷了 libs,头文件没拷。补上第 2 步的头文件拷贝后(共两处材料:libs + 头文件),构建通过。
构建成功
> hvigor Finished :entry:default@PackageHap... after 301 ms
> hvigor Finished :entry:default@SignHap... after 999 ms
> hvigor BUILD SUCCESSFUL in 9 s 112 ms
41 tasks in total: 26 executed, 15 up-to-date
产物(注意这次连签名都自动完成了):
entry/build/default/outputs/default/entry-default-signed.hap (26 MB)
entry/build/default/outputs/default/entry-default-unsigned.hap
SignHap 任务成功是因为 DevEco Studio 的自动签名已在此前打开工程时配置过(File → Project Structure → Signing Configs → Automatically generate signature),签名配置被写进了 openharmony/build-profile.json5 的 signingConfigs。这也修正了 hcordova 项目里"命令行产物必为 unsigned"的印象——只要 signingConfigs 存在,hvigorw 命令行构建同样会产出 signed HAP。
四、架构对照
4.1 capacitor-android vs @capacitor-ohos/ohos
| 维度 | Android | OHOS(openharmony-capacitor) |
|---|---|---|
| WebView | android.webkit.WebView | ArkWeb |
| 运行时分发 | gradle 依赖(jar/aar) | HAR 源码直接拷入工程(可读可改) |
| 桥接层 | Java + WebView JSBridge | ArkTS 容器 + C++ NAPI(Base64/Socket/SSLSocket/ConnPool/MemPool 等自研模块) |
| 网络栈 | java.net | 自研 C++ Socket/SSLSocket + openssl 3.x(需手动集成) |
| Web 资源 | assets/ | rawfile/www/(sync 拷入) |
| 插件注册 | CapacitorPluginAnnotation 扫描 | oh-plugins 目录 + capacitor.plugins.json |
4.2 hcordova vs hionic(同一 CPF 生态的姊妹 CLI)
| 维度 | hcordova | hionic |
|---|---|---|
| 框架 | Cordova | Capacitor(+ Cordova 兼容) |
| 版本(实测) | 1.0.7 | 2.1.16 |
| 平台运行时 | @cordova-ohos/ohos 14.0.2 | @capacitor-ohos/ohos 8.0.2 |
| openssl 自动安装 | ✅ 有(platform add ohos 交互式克隆编译) | ❌ 无(需手动集成,报错后才知道) |
| init 依赖 | 转发原版 cordova CLI(需 npm i -g cordova) | 调用 npx cap init(需项目内装 @capacitor/cli,见踩坑 1) |
| 模板渲染 | 43 个文件 | 48 个文件 |
| 命令丰富度 | create/platform/plugin + build(仅提示) | start/init/sync/copy/buildui/buildapp/run/open/info |
五、关键决策说明
决策 1:复用 hcordova 的 openssl 材料,而非从头编译
官方路线是按 openharmony-capacitor-openssl3.5 自行编译 openssl 3.5(Configure OHOS 交叉编译参数 → make)。本机 hcordova 项目里已有同源 openssl 3.x 编译产物(同样的 OHOS NDK clang 工具链、同样的 x86_64/arm64-v8a ABI、同样的 .so.3 命名),直接复用零成本通过验证。若没有 hcordova 项目垫底,则应走官方编译路线。
决策 2:手改 webDir 而非改 vite 产物目录
capacitor.config.json 的 webDir: www 与 Vite 惯例 dist 冲突。改配置一行 vs 改 vite.config 的 outDir 再全局约定——选前者,保持前端工程零改动原则。
决策 3:签名交给 DevEco 自动签名
模拟器/个人调试场景,DevEco 自动签名(登录华为账号一键生成 p12/cer/p7b 并写入 build-profile.json5)是最省事且可持续的方式;CI 场景再考虑 hap-sign-tool 手动签名链路。
六、测试与验证
| 验证项 | 结果 |
|---|---|
| Vite 构建 | ✅ 383ms,产出 dist/(222KB JS gzip 69KB) |
| sync 同步 | ✅ dist 内容进入 rawfile/www/,含 native-bridge.js |
| hvigorw 构建 | ✅ 41 任务(含 capacitor HAR 的 C++ NAPI 编译),9.1s |
| 签名 | ✅ SignHap 成功(DevEco 自动签名),产出 signed HAP |
| 包名核对 | ✅ hdc shell bm dump -n com.nutpi.MyApp |
运行:
hdc install -r openharmony/entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b com.nutpi.MyApp
七、踩坑复盘
| # | 踩坑点 | 现象 / 报错 | 根因与解法 |
|---|---|---|---|
| 1 | npx cap init 失败 | npm error could not determine executable to run(日志 pkgid cap@0.2.1) | hionic 未先给项目装 @capacitor/core + @capacitor/cli,npx 远端匹配到无关旧包 cap。解法:项目内 npm i @capacitor/core @capacitor/cli 后手动 npx cap init |
| 2 | openssl 库缺失 | ninja: error: 'libs/x86_64/libssl.so.3' ... missing and no known rule | hionic 无 openssl 自动安装(hcordova 有);CMakeLists 要求 capacitor/libs/<abi>/libssl.so.3。解法:拷入 hcordova 项目编译好的 openssl 3.x(或按官方 openharmony-capacitor-openssl3.5 仓库自行编译) |
| 3 | webDir 不匹配 | sync 报 Web directory not found: .../www 或同步了错误内容 | hionic 模板写死 webDir: www,Vite 产物在 dist。解法:改 capacitor.config.json 的 webDir 为 dist |
| 4 | openssl 头文件缺失 | fatal error: 'openssl/ssl.h' file not found(多个 .cpp) | CMake include 路径 cpp/openssl/<abi>/include 为空。解法:除 libs 外还需拷贝 openssl 头文件目录,两处材料缺一不可 |
| 5 | hvigorw 环境变量 | DEVECO_IDE_PATH is not configured(hionic buildapp 检查) | hionic 的 buildapp 要求两个环境变量:DEVECO_SDK_HOME 和 DEVECO_IDE_PATH(=/Applications/DevEco-Studio.app);hvigorw/ohpm/node 需加入 PATH |
| 6 | 命令行也能签名 | 之前以为 CLI 构建必产 unsigned HAP | 实际上只要 build-profile.json5 有 signingConfigs(DevEco 自动签名写入过),hvigorw 就会执行 SignHap 产出 signed HAP |
八、遗留问题与改进方向
已知问题
- hionic 未自动集成 openssl — 与 hcordova 相比是明显的能力缺口,建议在
add openharmony时检测capacitor/libs/是否存在并提示/自动下载(可对标 hcordova 的交互式 openssl 安装器) - hionic start 的 init 步骤不稳 — 依赖 npx 远端解析 cap 命令,需先装 @capacitor/cli(建议 hionic 在 create 流程中显式
npm i -D @capacitor/cli) - webDir 默认值与 Vite 不符 — react 模板应默认
dist
未来优化
- openssl 预编译 HAR 化:把 openssl 3.x so + 头文件做成 ohpm 包(如
@capacitor-ohos/openssl),让 CMake 直接依赖 oh_modules,免去手动拷贝 - 插件适配覆盖度:CPF-Ionic 已有 geolocation/haptics/clipboard/app-launcher/native-settings 等插件,常用插件的鸿蒙覆盖情况需逐一核验
九、总结
把一个 Vite + React 前端项目跑到 OpenHarmony 上,核心路径可以概括为三步走:
1. 接入 ── hionic start/init + add openharmony,生成 ArkWeb 壳工程,前端零改动
2. 补材料 ── 手动集成 openssl 3.x(libs + 头文件两处),hionic 未自动做
3. 循环 ── buildui → sync → hvigorw buildapp → 模拟器运行
与 hcordova 相比,hionic 的 Capacitor 路线工程现代化程度更高(HAR 源码运行时、插件注册透明、原生工程归开发者所有),但 openssl 集成是每个新项目都要踩的坑。两个 CLI 也可以共存协作:hcordova 项目里自动下载的 openssl 编译产物,恰好成为 hionic 项目的现成依赖——CPF 生态的 openssl 材料是同构的。
参考文档
更多推荐



所有评论(0)