从 H5 到 HarmonyOS:我做了一个 npm + OHPM 双端发布的 ArkWeb JSBridge 框架
前言
在很多 WebView 项目中,H5 调用 Native 的第一版代码通常很简单:
js
window.Native.postMessage(JSON.stringify({
action: 'showToast',
params: {
message: 'hello'
}
}));
这段代码确实可以完成通信。
但随着项目逐渐增加网络请求、本地存储、剪贴板、超时、并发调用、错误处理和 TypeScript 类型约束,最初的通信代码很容易变成一组难以维护的回调和 switch。
为了解决这些问题,我独立设计并实现了 MiniAppRuntime-Harmony。
它是一个基于 HarmonyOS、ArkTS 和 ArkWeb 公开能力实现的轻量级 Web 容器与 JSBridge 框架,由两个可以独立安装的包组成:
text
H5 SDK
→ npm
→ @lcy453/miniapp-runtime-harmony-web-sdk@0.1.0
ArkTS Runtime
→ OHPM
→ myascf_runtime@1.0.0
目前项目已经完成:
text
架构设计
→ H5 SDK
→ ArkTS Runtime
→ HAR 打包
→ npm 发布
→ OHPM 发布
→ React + HarmonyOS 独立 Demo
→ 公共包安装验证
→ 完整调用闭环
这篇文章会从四个角度介绍这个项目:
- 框架为什么这样设计。
- 开发者如何从零接入和使用。
- 一个框架从开发到 npm、OHPM 上线经历了什么。
- 这类项目对理解架构和准备 HarmonyOS 面试有什么帮助。
一、这个框架解决什么问题
假设一个 React 页面运行在 HarmonyOS ArkWeb 中。
页面希望完成这些操作:
text
显示系统 Toast
读写系统剪贴板
保存本地数据
发起网络请求
查询 Runtime 支持哪些 API
取消正在进行的请求
H5 本身不能直接调用 HarmonyOS 的 ArkTS API。
中间必须有一座桥:
text
H5
→ ArkWeb
→ ArkTS
→ HarmonyOS 系统能力
只把消息从 H5 传给 ArkTS 并不难,真正困难的是后续工程问题:
- 多个请求并发时,响应怎样找到对应的 Promise?
- Native 没有回调时,H5 是否会永远处于 pending?
- API 越来越多后,是否要维护一个巨大的
switch? - 参数校验应该放在通信层还是业务层?
- H5 SDK 和 ArkTS Runtime 应该怎样划分职责?
- 网络返回 404 时,到底应该 resolve 还是 reject?
- 用户取消请求后,晚到的 Native 响应如何处理?
- 文档、TypeScript 类型和 Runtime API 如何保持一致?
- 框架怎样打包,让其他项目不依赖本地源码就能安装?
MiniAppRuntime-Harmony 的目标,就是把这些问题整理成一套清晰、可扩展、可安装、可验证的工程结构。
二、最终使用效果
使用者不需要理解底层 Dispatcher、Registry、Biz 或 Imp。
H5 开发者先安装 SDK:
bash
npm install @lcy453/miniapp-runtime-harmony-web-sdk@0.1.0
然后像调用普通异步函数一样调用 HarmonyOS 能力:
ts
import {
createTypedApi,
initMyASCF
} from '@lcy453/miniapp-runtime-harmony-web-sdk';
const api = createTypedApi(initMyASCF());
await api.ui.showToast({
message: 'Hello HarmonyOS'
});
HarmonyOS 开发者安装 Runtime:
bash
ohpm install myascf_runtime@1.0.0
entry/oh-package.json5 中会出现:
json5
{
"dependencies": {
"myascf_runtime": "1.0.0"
}
}
然后在 ArkWeb 中注册 Runtime:
ts
import { webview } from '@kit.ArkWeb';
import { MyASCFRuntime } from 'myascf_runtime';
@Entry
@Component
struct Index {
private controller: webview.WebviewController =
new webview.WebviewController();
private runtime: MyASCFRuntime =
new MyASCFRuntime(
this.controller,
getContext(this)
);
build() {
Column() {
Web({
src: $rawfile('web/index.html'),
controller: this.controller
})
.javaScriptAccess(true)
.javaScriptProxy({
object: this.runtime.getNativeProxy(),
name: this.runtime.getProxyName(),
methodList: this.runtime.getMethodList(),
controller: this.controller
})
.width('100%')
.height('100%');
}
.width('100%')
.height('100%');
}
}
到这里,一条真正的公共包调用链就建立起来了:
text
npm H5 SDK
+
OHPM Runtime
+
ArkWeb JavaScriptProxy
=
H5 调用 HarmonyOS 能力
三、整体架构
项目的核心链路如下:
如果发布平台不支持 Mermaid,也可以直接理解为:
text
React / H5
→ H5 SDK
→ MyASCFNative.postMessage
→ JavaScriptProxy
→ BridgeController
→ BridgeDispatcher
→ HandlerRegistry
→ Biz
→ Imp
→ HarmonyOS API
→ runJavaScript
→ Promise
整套架构可以分成五层。
第一层:H5 业务层
React、Vue 或普通 H5 页面只负责调用:
ts
await api.system.storage.getItem({
key: 'username'
});
业务代码不需要直接拼接 JSON,也不需要自己管理 callback。
第二层:H5 SDK
H5 SDK 负责:
text
生成 requestId
保存 Promise callback
发送 Native 请求
设置 timeout
处理 AbortSignal
匹配 Native response
统一 resolve / reject
提供 TypeScript 类型
第三层:Bridge 协议层
BridgeController 负责:
text
解析 JSON
校验 requestId
校验 action
读取 params
构造统一响应
处理协议错误
BridgeController 不直接包含 Toast、Storage 或 Network 的业务实现。
第四层:分发与业务层
text
BridgeDispatcher
→ HandlerRegistry
→ Biz
→ Imp
Dispatcher 根据 action 查找 Handler。
Biz 负责参数校验和业务语义。
Imp 负责调用 HarmonyOS 公开能力。
第五层:回调层
Runtime 把统一的 BridgeResponse 通过 runJavaScript 回调 H5。
H5 SDK 再根据 requestId 找到对应 Promise。
四、为什么 requestId 是整个框架的核心
假设页面同时发起三个网络请求:
text
请求 A
请求 B
请求 C
它们的返回顺序可能是:
text
C
A
B
如果请求中只有 action:
text
network.request
H5 无法知道结果属于哪个 Promise。
因此,每次请求都必须生成唯一 requestId:
ts
{
requestId: 'myascf_xxx',
action: 'network.request',
params: {
url: 'https://example.com'
}
}
SDK 内部维护 callback map:
text
requestId
→ resolve
→ reject
→ timer
→ action
→ 创建时间
→ AbortSignal listener
Native response 返回后:
text
读取 response.requestId
→ 在 callback map 中查找
→ 清理 timer
→ 清理 listener
→ resolve 或 reject
这套设计主要解决三个问题:
- 并发请求。
- 响应乱序。
- Promise 生命周期管理。
这也是从"能通信的 Demo"走向"可复用 SDK"的关键一步。
五、为什么不用巨大的 switch
API 很少时,可以直接写:
ts
switch (request.action) {
case 'ui.showToast':
break;
case 'system.storage.getItem':
break;
case 'network.request':
break;
}
但 API 逐渐增加后,BridgeController 很容易同时承担:
text
JSON 解析
协议校验
API 查找
参数校验
业务规则
平台 API 调用
异常转换
回调
最后,一个文件会知道所有事情。
MiniAppRuntime-Harmony 使用注册和分发机制:
text
RuntimeBootstrap
→ HandlerRegistry
→ BridgeDispatcher
启动时把 action 和 Handler 建立映射:
text
ui.showToast
→ ToastBiz
system.storage.getItem
→ StorageBiz
network.request
→ NetworkBiz
新增 API 时,不需要改变 BridgeController 的主流程,只需要:
text
定义 action
→ 增加 Manifest
→ 实现 Biz
→ 实现 Imp
→ 在 Bootstrap 注册
→ 增加测试和 Demo
这里体现了一个很重要的架构思想:
稳定的主链路,不应该随着业务 API 的增加而不断修改。
六、Biz 和 Imp 为什么要分开
以 Toast 为例。
ToastBiz 负责什么
text
message 是否存在
message 是否为字符串
参数错误怎样转换
成功响应怎样生成
ToastImp 负责什么
text
真正调用 HarmonyOS Toast API
再以 Network 为例。
NetworkBiz
负责:
text
URL 是否合法
method 是否支持
timeout 是否合理
responseType 是否正确
HTTP 响应如何映射
错误如何转换
NetworkImp
负责:
text
创建 Native HTTP 请求
设置 headers
发送 body
读取 statusCode
读取 response body
销毁请求
这样拆分以后:
text
业务规则
和
平台实现
不会混在同一个类里。
它带来的好处包括:
- Biz 更容易做单元测试。
- HarmonyOS API 变化时主要修改 Imp。
- 参数错误不会散落在平台调用代码中。
- 不同 API 可以保持一致的错误和响应结构。
七、统一 BridgeResponse
所有 API 都遵守统一响应:
ts
interface BridgeResponse {
requestId: string;
code: number;
message: string;
data?: Record<string, unknown>;
action?: string;
duration?: number;
}
成功时:
json
{
"requestId": "myascf_xxx",
"code": 0,
"message": "success",
"data": {
"echoAction": "ui.showToast"
}
}
失败时:
json
{
"requestId": "myascf_xxx",
"code": 1001,
"message": "PARAM_ERROR: message is required"
}
H5 SDK 只需要遵守一个判断:
text
code === 0
→ Promise resolve
code !== 0
→ Promise reject
统一响应的意义是:
text
Toast 不再有一套回调
Storage 不再有一套回调
Network 不再有一套回调
业务调用方式始终一致。
八、API Manifest:让代码、类型和文档来自同一个来源
很多框架会分别维护:
text
Runtime action 列表
README API 表格
TypeScript 类型
Demo 按钮
维护时间久了,它们很容易互相不一致。
MiniAppRuntime-Harmony 使用 API Manifest 描述能力:
text
action
category
title
description
params
response
errors
implemented
Biz
Imp
example
internal
Manifest 可以驱动:
text
runtime.getApiList
README API 表格
API 文档
H5 TypeScript 类型
Typed API
一致性检查
当前 Manifest 包含 10 个 action:
text
9 个公开 API
1 个内部 action:network.abort
内部 action 不会作为普通业务 API 对外展示。
这里体现的是"单一事实来源"的思想:
能自动生成的内容,不要依赖人工复制维护多份。
九、当前提供的公开 API
1. runtime.getApiList
查询 Runtime 当前真正支持的 API:
ts
const response = await api.runtime.getApiList();
console.log(response.data?.apis);
适合用于:
- Demo 动态生成能力面板。
- 检查 SDK 与 Runtime 是否兼容。
- 调试 UNKNOWN_ACTION。
- 展示 Runtime 当前能力。
2. ui.showToast
ts
await api.ui.showToast({
message: '保存成功'
});
常见场景:
text
表单提交成功
复制成功
请求失败提示
设置保存完成
3. system.clipboard.writeText
ts
await api.system.clipboard.writeText({
text: 'ORDER-2026-001'
});
可以用于:
text
复制订单号
复制分享链接
复制兑换码
复制调试信息
4. system.clipboard.readText
ts
const response =
await api.system.clipboard.readText();
console.log(response.data?.text);
剪贴板读取涉及宿主权限配置,实际应用应按照 HarmonyOS 权限要求完成声明和用户授权。
5. system.storage.setItem
当前 Storage 使用 Preferences 保存字符串键值:
ts
await api.system.storage.setItem({
key: 'username',
value: 'lichenyang'
});
6. system.storage.getItem
ts
const response =
await api.system.storage.getItem({
key: 'username'
});
console.log(response.data?.value);
7. system.storage.removeItem
ts
await api.system.storage.removeItem({
key: 'username'
});
8. system.storage.clear
ts
await api.system.storage.clear();
9. network.request
ts
const response = await api.network.request({
url: 'https://example.com',
method: 'GET',
responseType: 'text',
timeout: 10000
}, {
timeout: 12000
});
console.log(response.data?.statusCode);
console.log(response.data?.ok);
console.log(response.data?.body);
Network 是项目中异步生命周期最完整的 API。
它覆盖:
text
GET
POST
headers
body
text/json response
Native timeout
H5 callback timeout
HTTP 非 2xx
AbortController
并发请求
取消后的晚到响应
十、HTTP 404 为什么不直接 reject
这是 Network 设计中很重要的一点。
假设服务器返回:
text
404 Not Found
从 HTTP 角度看,请求不是 2xx。
但是从 Bridge 角度看:
text
H5 请求成功进入 ArkTS
Runtime 成功发起请求
服务器成功返回 HTTP 响应
Runtime 成功把响应传回 H5
所以 Bridge 链路是成功的。
当前语义是:
text
HTTP 200
→ Promise resolve
→ data.ok = true
HTTP 404 / 500
→ Promise resolve
→ data.ok = false
→ data.statusCode 保留真实状态
连接失败、网络超时
→ Promise reject
业务层应该这样判断:
ts
const response = await api.network.request({
url: 'https://example.com/not-found'
});
if (!response.data?.ok) {
console.error(
'HTTP failed:',
response.data?.statusCode
);
}
这里体现的是:
HTTP 状态错误,不等于 Bridge 通信链路错误。
十一、两层 timeout
网络调用中存在两个不同的 timeout。
Native 网络 timeout
位于请求参数:
ts
{
timeout: 10000
}
它控制 ArkTS HTTP 请求等待网络结果的时间。
H5 callback timeout
位于 SDK options:
ts
{
timeout: 12000
}
它控制 H5 等待 Native callback 的时间。
完整示例:
ts
await api.network.request({
url: 'https://example.com',
timeout: 10000
}, {
timeout: 12000
});
通常建议:
text
H5 callback timeout
略大于
Native 网络 timeout
这样 Native 有机会先返回明确的网络超时错误,而不是由 H5 提前结束等待。
十二、AbortController 与请求取消
H5 可以使用 Web 开发者熟悉的 AbortController:
ts
const controller = new AbortController();
const task = api.network.request({
url: 'https://example.com/slow',
method: 'GET'
}, {
timeout: 12000,
signal: controller.signal
});
controller.abort();
try {
await task;
} catch (error) {
console.log('request aborted', error);
}
SDK 取消请求时会处理:
- 从 callback map 删除当前请求。
- 清理 timeout timer。
- 移除 AbortSignal listener。
- reject 当前 Promise。
- 发送内部
network.abort。 - Runtime 尝试终止 Native 网络任务。
- 忽略取消后的晚到响应。
这里体现的是异步框架中的一个重要原则:
取消不仅仅是 reject Promise,还要清理整个请求生命周期。
十三、普通浏览器为什么会出现 NATIVE_UNAVAILABLE
H5 SDK 可以在 Chrome 中正常安装、构建和初始化。
但是普通浏览器没有 ArkWeb 注入的:
ts
window.MyASCFNative
因此调用 Native API 时会 reject:
text
NATIVE_UNAVAILABLE
这并不代表 npm SDK 安装失败。
它反而说明:
text
ESM import 成功
SDK 初始化成功
Promise 错误边界生效
Native 环境检测生效
真正调用 Toast、Storage、Clipboard 和 Network,需要运行在已经注册 Runtime 的 ArkWeb 中。
可以在页面里检测环境:
js
JSON.stringify({
myascfType: typeof window.myascf,
nativeType: typeof window.MyASCFNative,
postMessageType:
typeof window.MyASCFNative?.postMessage,
callbackType:
typeof window.__myascf_on_native_response__
});
十四、从零接入完整流程
下面以 React + Vite + HarmonyOS Stage Model 工程为例。
第一步:创建 React 项目
bash
npm create vite@latest web-demo -- --template react-ts
cd web-demo
npm install
安装 H5 SDK:
bash
npm install @lcy453/miniapp-runtime-harmony-web-sdk@0.1.0
第二步:配置 Vite
vite.config.ts:
ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
base: './',
build: {
target: 'es2017'
}
});
这里的:
ts
base: './'
非常重要。
页面最终会放进 HarmonyOS rawfile。如果使用以 / 开头的绝对静态资源路径,ArkWeb 加载本地页面时可能找不到 JS 和 CSS。
第三步:初始化 SDK
src/App.tsx:
tsx
import { useState } from 'react';
import {
createTypedApi,
initMyASCF
} from '@lcy453/miniapp-runtime-harmony-web-sdk';
const api = createTypedApi(initMyASCF());
export default function App() {
const [result, setResult] =
useState('等待调用');
async function showToast(): Promise<void> {
try {
const response =
await api.ui.showToast({
message: 'Hello HarmonyOS'
});
setResult(
JSON.stringify(response, null, 2)
);
} catch (error: unknown) {
setResult(
JSON.stringify(error, null, 2)
);
}
}
return (
<main>
<h1>MiniAppRuntime-Harmony</h1>
<button
onClick={() => void showToast()}
>
Show Toast
</button>
<pre>{result}</pre>
</main>
);
}
第四步:构建 H5
bash
npm run build
把 dist 内容放进:
text
entry/src/main/resources/rawfile/web/
最终类似:
text
rawfile/web/
├─ index.html
└─ assets/
第五步:安装 OHPM Runtime
进入 HarmonyOS 模块目录:
bash
ohpm install myascf_runtime@1.0.0
确认:
json5
{
"dependencies": {
"myascf_runtime": "1.0.0"
}
}
第六步:配置权限
在 entry/src/main/module.json5 中按需声明:
json5
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.READ_PASTEBOARD",
"reason": "$string:pasteboard_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
}
}
用途:
text
network.request
→ ohos.permission.INTERNET
system.clipboard.readText
→ ohos.permission.READ_PASTEBOARD
→ 还需要运行时授权
权限属于宿主应用责任,Runtime 不应绕过系统权限模型。
第七步:注册 JavaScriptProxy
ts
import { webview } from '@kit.ArkWeb';
import { MyASCFRuntime } from 'myascf_runtime';
@Entry
@Component
struct Index {
private controller: webview.WebviewController =
new webview.WebviewController();
private runtime: MyASCFRuntime =
new MyASCFRuntime(
this.controller,
getContext(this)
);
build() {
Web({
src: $rawfile('web/index.html'),
controller: this.controller
})
.javaScriptAccess(true)
.javaScriptProxy({
object: this.runtime.getNativeProxy(),
name: this.runtime.getProxyName(),
methodList: this.runtime.getMethodList(),
controller: this.controller
})
.width('100%')
.height('100%');
}
}
第八步:运行
在 DevEco Studio 中执行:
text
Sync and Refresh Project
→ Clean Project
→ Rebuild Project
→ Run
建议依次验证:
text
runtime.getApiList
ui.showToast
Clipboard write/read
Storage set/get/remove/clear
Network GET
Network POST
HTTP 非 2xx
AbortController
错误链路
十五、为什么要分别发布 npm 和 OHPM
这个框架由两个运行在不同环境的部分组成。
H5 SDK 属于前端生态
它面向:
text
JavaScript
TypeScript
React
Vue
Vite
浏览器构建工具
所以发布到 npm。
Runtime 属于 HarmonyOS 生态
它面向:
text
ArkTS
ArkWeb
HAR
DevEco Studio
HarmonyOS 工程
所以发布到 OHPM。
如果把二者强行塞进一个包中,容易出现:
text
前端开发者安装了不需要的 ArkTS 内容
HarmonyOS 开发者需要手动复制 H5 SDK
版本边界不清晰
发布流程混乱
拆分以后:
text
H5 SDK 负责协议客户端
Runtime 负责协议服务端
两边可以独立构建、独立测试、独立发布,并通过版本兼容关系协作。
十六、H5 SDK 的上线流程
H5 SDK 的发布链路是:
text
TypeScript 源码
→ 类型生成
→ ESM 构建
→ IIFE 构建
→ d.ts 构建
→ 单元测试
→ npm pack dry-run
→ 外部 Consumer 验证
→ npm publish
项目提供:
text
ESM
IIFE
TypeScript 类型声明
package exports
prepublishOnly 检查
典型检查:
bash
cd h5_sdk
npm install
npm run check
npm pack --dry-run
发布前最重要的不是立即执行 npm publish,而是先确认:
text
包中包含哪些文件
exports 是否正确
类型声明能否被消费
外部项目能否安装
普通浏览器错误边界是否正确
发布以后,还需要在独立 React 项目里重新从 npm 安装,避免误用工作区源码或本地 tar 包。
十七、Runtime HAR 的上线流程
Runtime 发布链路是:
text
ArkTS 源码
→ Hvigor 构建 HAR
→ 检查 HAR 元数据
→ 检查包内 README
→ ohpm prepublish
→ SHA-256
→ ohpm publish
→ OHPM 审核
→ 公共包安装验证
Runtime 包信息:
text
name: myascf_runtime
version: 1.0.0
artifactType: original
license: MIT
安装命令需要明确写入包内 README:
bash
ohpm install myascf_runtime
或:
bash
ohpm install myascf_runtime@1.0.0
发布前需要确认:
text
README 已经进入最终 HAR
包名和版本正确
repository 是有效 URL
ohpm prepublish 通过
没有把密钥和签名信息打进包
OHPM 审核通过以后,还不能立即认为结束。
最重要的一步是:
新建一个不引用仓库源码的独立 Demo,通过 OHPM 公共包重新安装 Runtime。
例如:
json5
{
"dependencies": {
"myascf_runtime": "1.0.0"
}
}
这一步通过,才能证明分发闭环真正成立。
十八、为什么独立 Consumer Demo 很重要
仓库内 Demo 能运行,只能证明:
text
源码
和
源码
可以一起工作
但其他开发者使用的是:
text
npm Registry 中的 H5 SDK
OHPM 中的 Runtime
因此,独立 Demo 必须做到:
text
不引用 Runtime 源码
不复制本地 HAR
不使用 file:
不使用 workspace
不依赖作者电脑路径
MiniAppRuntime-Harmony 的独立 Demo 使用:
text
React + TypeScript + Vite
+
HarmonyOS Stage Model
+
公共 npm 包
+
公共 OHPM 包
并验证:
text
Toast
API List
Clipboard
Storage
Network
HTTP 非 2xx
AbortController
错误链路
这一步的价值甚至高于"仓库源码 Demo 跑通"。
因为它验证的是:
其他开发者是否真的可以按照 README 安装和使用。
十九、这个项目体现了哪些架构思想
1. 协议优先
先定义请求和响应,再实现具体 API:
text
requestId
action
params
BridgeResponse
2. 关注点分离
text
H5 SDK
Bridge
Dispatcher
Registry
Biz
Imp
Callback
每一层只处理自己的问题。
3. 稳定主链路
新增 API 不修改 BridgeController 主流程。
4. 注册驱动
API 与 Handler 通过 Registry 建立关系,而不是堆积 switch。
5. 单一事实来源
Manifest 同时驱动类型、文档和运行时能力查询。
6. 统一错误模型
不同系统 API 最终都转换成一致的 Promise 成功或失败。
7. 异步生命周期治理
不仅处理成功,还要处理:
text
timeout
cancel
callback lost
late response
invalid response
8. 可观测性
通过 requestId、action、duration 和 DebugPanel 观察完整调用链。
9. 真实消费验证
最终验证对象不是源码,而是公开发布的包。
二十、适合在哪里使用
这个项目适合以下场景:
text
HarmonyOS 应用内嵌 H5
React 或 Vue 页面调用 ArkTS 能力
已有 Web 业务逐步接入 HarmonyOS
需要统一 Promise API 的 ArkWeb 容器
学习 ArkWeb 双向通信
学习 HAR 封装和 OHPM 发布
学习 npm SDK 工程化
构建轻量级混合应用能力层
一个典型业务结构是:
text
多个 H5 页面
→ 只依赖同一套 H5 SDK
→ 通过统一 action 调用 Runtime
→ Runtime 统一管理平台能力
这样能够避免每个页面都单独实现一套 Native 通信代码。
二十一、这个项目对就业和面试有什么帮助
这个项目不会因为发布了 npm 和 OHPM 包,就自动成为"权威框架"。
但它确实比普通页面 Demo 更能证明一个开发者的综合能力。
普通业务 Demo 通常证明什么
text
会写页面
会使用组件
会调用少量系统 API
这个项目还能证明什么
text
理解 ArkWeb
理解 JavaScriptProxy
理解 H5 与 ArkTS 通信
能设计 Promise SDK
能处理异步生命周期
能设计分发和注册机制
能划分 Biz 与 Imp
能生成 TypeScript 类型
能发布 npm 包
能发布 OHPM HAR
能编写独立消费 Demo
能维护文档和版本
它覆盖的能力可以总结为:
| 能力方向 | 项目体现 |
|---|---|
| HarmonyOS | ArkTS、ArkWeb、HAR、OHPM、权限、系统能力 |
| 前端 | React、Vite、TypeScript、Promise、AbortController |
| 架构 | Dispatcher、Registry、Biz/Imp、统一协议 |
| 工程化 | Manifest、类型生成、测试、CI、发布检查 |
| 开源 | README、教程、Demo、npm、OHPM、版本发布 |
| 调试 | requestId、日志、DebugPanel、错误链路 |
二十二、面试时可以怎样介绍
不建议说:
text
我做了一个非常权威的 HarmonyOS 框架
更可信的表达是:
我独立设计并实现了一个基于 HarmonyOS ArkWeb 的轻量级 JSBridge 框架。H5 侧是发布到 npm 的 TypeScript SDK,HarmonyOS 侧是发布到 OHPM 的 ArkTS HAR Runtime。SDK 使用 requestId 和 callback map 管理 Promise,通过 JavaScriptProxy 进入 ArkTS,再经过 Dispatcher、Registry、Biz 和 Imp 调用 HarmonyOS 系统能力,最后通过 runJavaScript 返回 H5。项目已经完成 npm、OHPM 和独立公共包 Demo 验证。
面试官继续追问时,可以重点讲:
text
为什么拆成两个包
为什么需要 requestId
为什么不用 switch
为什么 Biz 和 Imp 分层
HTTP 404 为什么 resolve
timeout 为什么分两层
AbortController 如何清理资源
Manifest 怎样生成类型和文档
独立 Demo 为什么比源码 Demo 更重要
这些问题都有真实代码和真实发布过程支撑,而不是只背架构名词。
二十三、当前边界
项目目前定位是个人开源工程实践。
它不应该被描述为:
text
HarmonyOS 官方方案
生产级万能框架
大型商业项目的直接替代品
完整安全沙箱
兼容所有设备和系统版本
真正的大规模生产环境还需要继续考虑:
text
多 Web 实例隔离
来源和域名安全校验
消息权限模型
大数据传输
性能压测
内存治理
生命周期恢复
多设备兼容
版本协商
灰度升级
线上监控
明确边界不会削弱项目价值,反而能体现开发者对工程现实的理解。
二十四、项目现在完成到了什么程度
MiniAppRuntime-Harmony 当前已经完成:
text
最小 JavaScriptProxy 通信
→ Promise SDK
→ requestId 与 callback map
→ Dispatcher / Registry
→ Biz / Imp
→ Toast / Clipboard / Storage / Network
→ timeout 与 AbortController
→ API Manifest
→ TypeScript Typed API
→ npm 发布
→ HAR 构建
→ OHPM 发布
→ 独立公共包 Demo 验证
→ 文档体系
它已经不只是一个通信 Demo,而是完成了一个框架项目从设计到分发的完整生命周期。
总结
MiniAppRuntime-Harmony 最值得总结的,不是实现了多少个 API,而是完整回答了这些问题:
text
H5 怎样调用 HarmonyOS?
多个异步请求怎样匹配?
Native 不回调怎么办?
API 怎样扩展?
参数校验放在哪里?
平台代码怎样隔离?
错误怎样统一?
类型和文档怎样同步?
H5 SDK 怎样发布?
ArkTS Runtime 怎样发布?
其他开发者怎样验证安装?
最终形成的调用链是:
text
React / H5
→ npm H5 SDK
→ JavaScriptProxy
→ ArkTS Runtime
→ Dispatcher / Registry
→ Biz / Imp
→ HarmonyOS API
→ runJavaScript
→ H5 Promise
安装 H5 SDK:
bash
npm install @lcy453/miniapp-runtime-harmony-web-sdk@0.1.0
安装 Runtime:
bash
ohpm install myascf_runtime@1.0.0
项目地址:
对于正在学习 HarmonyOS、ArkWeb、跨端通信或前端 SDK 工程化的开发者,这个项目可以作为一个从"能运行"逐步走向"可设计、可安装、可发布、可维护"的完整案例。