从 H5 到 HarmonyOS:我做了一个 npm + OHPM 双端发布的 ArkWeb JSBridge 框架

从 H5 到 HarmonyOS:我做了一个 npm + OHPM 双端发布的 ArkWeb JSBridge 框架

项目地址:github.com/lichenyang5...

前言

在很多 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
→ 公共包安装验证
→ 完整调用闭环

这篇文章会从四个角度介绍这个项目:

  1. 框架为什么这样设计。
  2. 开发者如何从零接入和使用。
  3. 一个框架从开发到 npm、OHPM 上线经历了什么。
  4. 这类项目对理解架构和准备 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 能力

三、整体架构

项目的核心链路如下:

flowchart LR H5["React / Vue / H5"] --> SDK["npm H5 SDK"] SDK --> Send["window.myascf.send"] Send --> Native["MyASCFNative.postMessage"] Native --> Proxy["ArkWeb JavaScriptProxy"] Proxy --> Controller["BridgeController"] Controller --> Dispatcher["BridgeDispatcher"] Dispatcher --> Registry["HandlerRegistry"] Registry --> Biz["Biz Layer"] Biz --> Imp["Imp Layer"] Imp --> Kit["HarmonyOS Public API"] Kit --> Response["BridgeResponse"] Response --> Executor["BridgeCallbackExecutor"] Executor --> RunJS["runJavaScript"] RunJS --> Callback["H5 callback map"] Callback --> Promise["Promise resolve / reject"]

如果发布平台不支持 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

这套设计主要解决三个问题:

  1. 并发请求。
  2. 响应乱序。
  3. 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 取消请求时会处理:

  1. 从 callback map 删除当前请求。
  2. 清理 timeout timer。
  3. 移除 AbortSignal listener。
  4. reject 当前 Promise。
  5. 发送内部 network.abort
  6. Runtime 尝试终止 Native 网络任务。
  7. 忽略取消后的晚到响应。

这里体现的是异步框架中的一个重要原则:

取消不仅仅是 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

项目地址:

github.com/lichenyang5...

对于正在学习 HarmonyOS、ArkWeb、跨端通信或前端 SDK 工程化的开发者,这个项目可以作为一个从"能运行"逐步走向"可设计、可安装、可发布、可维护"的完整案例。

相关推荐
用户84298142418101 小时前
AI时代,JS混淆加密还有用吗?
前端·javascript
xiaobaoyu1 小时前
如何理解前端项目中的绝对路径和相对路径
前端
xiaobaoyu1 小时前
vue3+vite+vant4项目实战总结
前端
咖啡星人k1 小时前
【无标题】
前端·ai·github
颜进强1 小时前
LangChain 从入门到实践:用最小案例理解 RAG 的 5 个核心抽象
前端·后端·ai编程
颜进强1 小时前
MCP 从入门到实践:用 TypeScript 实现第一个 MCP Server
前端·后端·ai编程
朕的剑还未配妥2 小时前
CSS 实现渐变毛玻璃:从 backdrop-filter 到多层 mask
前端·css
程序员黑豆2 小时前
鸿蒙开发实战:使用 List 组件构建新闻列表
前端·华为·harmonyos
xiaobaoyu2 小时前
谈谈你对iframe的了解
前端