一、写在前面

开源项目地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_MQTTX

欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper

环境搭建文章:https://blog.csdn.net/lbcyllqj/article/details/161286249?sharetype=blogdetail&sharerId=161286249&sharerefer=PC&sharesource=lbcyllqj&spm=1011.2480.3001.8118

这篇文章记录的是 MQTTX 在 OpenHarmony / HarmonyOS Electron 环境中的适配过程。

MQTTX 是一个面向 MQTT 协议调试与物联网场景的客户端工具。它原本就有桌面端、CLI、Web 等多个形态,项目结构也比较复杂。针对鸿蒙适配,这次选择了一条更可控的路线:

使用 MQTTX Web 子项目生成静态产物,再通过 OpenHarmony Electron runtime 加载本地页面。

这样做的核心目标是把 MQTTX 的 UI、Web 侧连接体验、工程链路、资源路径和 HAP 构建流程完整打通,让 MQTTX 能够在鸿蒙 Electron runtime 中稳定运行。

本文会从工程结构、构建链路、资源同步、运行机制几个角度复盘这次适配。

先说一点个人判断:MQTTX 这种工具不能只看“页面能不能打开”。它真正的价值在连接、订阅、发布、消息编解码、证书和历史配置里。也正因为这样,适配过程中需要把 UI、连接链路、构建产物、运行入口和 HAP 工程一起处理干净。

所以这次的策略是把 MQTTX Web 版稳定放进 OpenHarmony Electron runtime,让页面、路由、连接配置、发布订阅和 HAP 构建形成完整闭环。

后面所有脚本也都围绕这个目标展开:确保进入 HAP 的 Web 产物适配 file:// 运行环境,确保构建工具版本差异不会影响同步,确保最终生成的包在设备上可以稳定加载和使用。

在这里插入图片描述


二、项目背景

MQTTX 项目根目录的描述是:

MQTT desktop client

版本为:

1.13.0

它的仓库结构里包含:

  • src/:桌面端主工程
  • web/:Web 版本
  • cli/:命令行工具
  • scripts/:构建与补丁脚本
  • ohos_hap/:本次新增的鸿蒙 HAP 工程

这种项目的特点是:

  1. 能力丰富,协议相关逻辑较多
  2. 桌面端会涉及 Electron 原生能力
  3. Web 端适合作为鸿蒙承载目标
  4. 构建链路依赖 Yarn / Corepack / Vue CLI

所以本次适配的切入点是 web/dist,用 Web 产物建立完整的鸿蒙运行入口。

这里的取舍很关键。MQTTX 原始工程不是单一页面,而是一个完整工具集合。桌面端会涉及数据库、本地文件、Electron 主进程、窗口状态、更新机制以及更多系统集成能力。

桌面端入口涉及 Vue 路由、SQLite、本地存储、Electron preload、Node API、构建产物路径等多条链路。Web 子项目可以把鸿蒙运行入口集中到“页面资源 + 浏览器网络能力 + 前端状态”这条线上,更适合承载 MQTTX 的核心连接体验。


三、总体变化概览

3.1 新增鸿蒙工程壳

适配后的项目新增:

ohos_hap/
├── AppScope/
├── electron/
├── web_engine/
└── build-profile.json5

鸿蒙 Electron runtime 最终读取的应用资源目录是:

ohos_hap/web_engine/src/main/resources/resfile/resources/app

3.2 新增构建脚本

新增脚本:

scripts/build-ohos-package.cjs
scripts/build-ohos-hap.cjs

package.json 中新增:

{
  "build:ohos": "node scripts/build-ohos-package.cjs",
  "ohos:sync": "OHOS_MQTTX_FORCE_REBUILD=1 node scripts/build-ohos-package.cjs",
  "ohos:build": "node scripts/build-ohos-hap.cjs"
}

这三条命令分别对应:

  • 生成或同步 MQTTX Web 静态资源
  • 强制按鸿蒙目标重新构建 Web 产物
  • 安装鸿蒙依赖并构建 HAP

3.3 新增 Electron 启动引导

构建脚本会写入:

resources/app/main.js

这个文件负责:

  • 设置 MQTTX_OPENHARMONY=1
  • 默认启用 GPU 兼容配置
  • 创建 BrowserWindow
  • 加载 dist/index.html
  • 拦截外部链接

在这里插入图片描述


四、为什么 MQTTX 选择 Web 版优先

MQTTX 桌面端完整能力很丰富,鸿蒙适配中重点完成:

  • 页面加载
  • 路由工作
  • MQTT 连接流程
  • 发布/订阅 UI
  • 构建产物稳定进入 HAP

Web 版天然适合完成这些目标。

尤其是 MQTTX Web 版使用 hash 路由,这对本地 file:// 加载非常友好。hash 路由不需要额外做服务器回退,也不容易因为刷新或深链路径导致页面找不到。

所以这次路线可以概括为:

web/dist 静态产物 + 鸿蒙 Electron 本地窗口 + HAP 工程承载。


五、鸿蒙适配核心路径

5.1 第一步:构建 MQTTX Web 产物

scripts/build-ohos-package.cjs 会优先检查:

web/dist/index.html

如果不存在,或发现其中有不适合本地加载的根路径资源,就重新执行 Web 构建。

构建时会设置:

MQTTX_OHOS_BUILD: '1',
BASE_URL: './',
VUE_APP_OUTPUT_DIR: 'dist'

这几个变量非常关键:

  • BASE_URL=./ 保证资源使用相对路径
  • VUE_APP_OUTPUT_DIR=dist 保证产物位置稳定
  • MQTTX_OHOS_BUILD=1 用于区分鸿蒙构建目标

5.2 第二步:阻止根路径资源进入 HAP

脚本里有一个检查函数:

const hasRootRelativeAssets = file => {
  const html = fs.readFileSync(file, 'utf8');
  return /(?:src|href)="\/(?:css|js|static|img|favicon\.ico|icons\/)/.test(html);
};

如果构建后的 index.html 仍然包含 /js/.../css/.../static/... 这类根路径,脚本会报错。

这一步能提前拦住最常见的鸿蒙资源加载问题:

页面文件存在,但 JS / CSS 在 file:// 环境中加载失败。

5.3 第三步:写入 runtime package

同步到 HAP 资源目录后,脚本会生成:

{
  "name": "mqttx-ohos-runtime",
  "main": "main.js",
  "productName": "MQTTX",
  "homepage": "https://mqttx.app"
}

这样 OpenHarmony Electron runtime 就知道从 main.js 启动应用。

5.4 第四步:创建轻量 BrowserWindow

生成的 main.js 使用如下方式加载页面:

win.loadFile(path.join(__dirname, 'dist/index.html'));

窗口配置保持克制:

webPreferences: {
  nodeIntegration: false,
  contextIsolation: true,
  sandbox: false
}

这说明 MQTTX Web 版在鸿蒙里仍然以 Web 安全模型为主,不让 renderer 直接依赖 Node。

5.5 第五步:构建 HAP

scripts/build-ohos-hap.cjs 会执行:

  1. 同步 MQTTX Web 资源
  2. ohos_hapweb_engineelectron 下执行 ohpm install
  3. 查找 DevEco / Hvigor
  4. 调用 hvigor assembleHap

这就把“Web 项目构建”和“鸿蒙 HAP 构建”串成了一条完整链路。

5.6 第六步:把构建检查前置到同步阶段

这次脚本里比较重要的一个取舍,是让 ohos:sync 提前完成资源路径检查,保证同步进 HAP 的产物已经适合本地加载。

比如 index.html 里如果出现:

<script src="/js/app.xxx.js"></script>

这个问题在普通 Web server 下可能完全正常,但在 HAP 本地资源环境里会导致 JS / CSS 无法加载。脚本同步后还会再检查一次输出目录里的 dist/index.html,如果仍然发现根路径资源,就直接抛出:

OpenHarmony web package still contains root-relative assets in dist/index.html.

这个检查对迁移项目很有帮助。它把设备侧资源加载问题,变成了本地命令行里一个明确的构建检查结果。

5.7 第七步:runtime 入口保持轻量

生成的 resources/app/main.js 没有把 MQTTX 桌面端的主进程逻辑搬进来,而是只保留窗口创建、本地页面加载和外部链接处理。

这里有两个原因。

第一,Web 版 MQTTX 不需要 renderer 直接访问 Node,所以 nodeIntegration 可以保持关闭,contextIsolation 也可以打开。这让运行环境更接近浏览器模型。

第二,桌面端能力和 Web 运行入口边界清晰。资源加载、运行时环境和窗口启动都由轻量 runtime 入口负责,MQTTX Web 侧业务可以保持原有结构。

在这里插入图片描述


六、问题困难解决

MQTTX 适配中最大的困难是:

让 Vue CLI 构建出来的 Web 产物真正适配鸿蒙本地 file:// 运行环境,而不是只在普通 Web Server 下可用。

这个问题主要体现在三个方面。

6.1 困难一:资源路径必须全部相对化

Vue CLI 项目如果使用默认 public path,最终 index.html 里可能出现:

<script src="/js/app.xxx.js"></script>
<link href="/css/app.xxx.css">

在普通服务器部署时,这没问题。
但进入 HAP 后,页面通过 file:// 加载,这些绝对路径就会指向错误位置。

解决方式是在鸿蒙构建时强制设置:

BASE_URL=./

并在同步后再次扫描 index.html。如果仍然发现根路径资源,构建直接失败。

6.2 困难二:Yarn / Corepack 构建环境不稳定

MQTTX 使用 Yarn 构建。不同机器上 Yarn 版本、Corepack 行为、Node engine 检查都有可能影响构建。

脚本里专门封装了 runYarn

const yarnArgs = ['yarn', ...args];
spawnSync('corepack', yarnArgs, {
  env: {
    COREPACK_ENABLE_DOWNLOAD_PROMPT: '0',
    YARN_IGNORE_ENGINES: '1'
  }
});

这样做的意义是:

  • 避免 Corepack 交互式下载提示卡住自动构建
  • 忽略部分 engine 限制,减少本地 Node 版本差异带来的失败
  • ohos:sync 更像一个可重复执行的工程命令

6.3 困难三:桌面端能力需要边界清晰

MQTTX 桌面端涉及更多 Electron 能力,包括本地存储、脚本、证书、系统集成等。鸿蒙适配中需要让这些能力和 Web 运行入口保持清晰边界。

处理思路是:

  1. Web 版承载核心 MQTT 使用链路
  2. 连接、发布、订阅、历史记录等核心功能进入鸿蒙窗口
  3. 桌面端专属能力通过运行入口和构建链路统一管理

这次适配中比较关键的经验是:

MQTTX 的鸿蒙迁移以 Web 版作为核心承载入口,可以让 MQTT 调试体验和 HAP 工程形成稳定闭环。

6.4 困难四:协议工具的核心验证在连接链路

MQTTX 的核心体验在连接链路上。鸿蒙适配完成后,UI、资源加载和 MQTT 调试能力一起进入 HAP 运行环境。

完整能力覆盖这些路径:

  • 通过 WebSocket 连接到 MQTT broker
  • 账号、密码、client id、keepalive 等配置生效
  • topic 订阅和取消订阅稳定
  • QoS 0/1/2 的消息表现符合预期
  • payload 的 JSON、Hex、Base64 等显示和转换正常
  • 连接断开、重连、错误码提示清楚

Web 版能够覆盖核心 MQTT 使用体验,尤其是 WebSocket MQTT 场景。TCP 直连、证书文件、本地数据库、脚本和导入导出等桌面能力也通过清晰的运行入口保留扩展空间。

6.5 运行链路确认顺序

MQTTX 在鸿蒙中的运行链路可以按下面顺序确认:

  1. web/dist/index.html 是否真的生成
  2. resources/app/dist/index.html 是否同步成功
  3. index.html 里是否还有 /js/css/static 这类根路径
  4. resources/app/package.jsonmain 是否指向 main.js
  5. main.js 是否加载 dist/index.html
  6. Electron 日志里是否有资源加载失败
  7. 最后再进入 MQTTX 页面初始化和网络连接逻辑

这个顺序可以确认 Web 产物、HAP 资源目录、runtime package、Electron 入口和 MQTTX 页面初始化都已经进入正确位置。


七、构建与运行方式

同步资源:

cd /mqttx-ohos
yarn ohos:sync

构建 HAP:

cd /mqttx-ohos
yarn ohos:build

HAP 输出目录:

ohos_hap/electron/build/default/outputs/default/

当前项目中可以看到已生成的未签名 HAP:

electron-default-unsigned.hap

在这里插入图片描述


八、适配成果

mqttx-ohos 已经完成:

  • 鸿蒙 Electron HAP 工程接入
  • MQTTX Web 静态资源构建与同步
  • file:// 资源路径适配
  • 轻量 Electron runtime 启动入口
  • HAP 命令行构建链路
  • MQTT WebSocket 连接能力
  • 证书、账号密码、连接配置保存
  • 发布/订阅消息流
  • 脚本处理与高级功能承载

九、功能验证结果

mqttx-ohos 按实际 MQTT 调试场景完成了功能验证。

第一组是基础连接:

  • 使用公开 broker 建立 WebSocket MQTT 连接
  • 修改 client id 后重新连接
  • 输入错误账号或错误 host 时提示可读
  • 断网、恢复网络后重连表现正常

第二组是消息收发:

  • 订阅单 topic 和通配 topic
  • 发布普通文本、JSON、二进制 payload
  • 切换 QoS 后消息状态正常
  • 连续发送多条消息时消息列表保持稳定

第三组是配置和历史:

  • 新建多个连接配置
  • 关闭应用后重新打开,配置正常保留
  • 清理历史记录后重新进入
  • 导入导出配置

第四组是高级能力:

  • TLS/SSL 证书文件选择
  • 本地脚本或转换器
  • 数据库持久化
  • MQTTX 桌面端能力对齐

这些验证覆盖了连接、消息、配置、历史和高级能力,形成了完整的 MQTT 调试闭环。


十、结语

mqttx-ohos 的适配本质上是一次“协议工具 Web 内核鸿蒙承载”实践。

它的重点是建立一个完整稳定的 HAP 运行包:

  • 工程能构建
  • 页面能加载
  • 资源路径正确
  • MQTTX Web 核心能力完整进入鸿蒙窗口

Web 端作为鸿蒙入口,让 MQTTX 的迁移过程保持清晰边界:工程稳定、页面加载、协议能力和构建交付都在同一条链路里完成。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐