鸿蒙 + Electron 跨端开发进阶实战:从桌面应用到鸿蒙多设备协同(附完整代码)
引言:跨端开发的破局之路 —— 鸿蒙与 Electron 的强强联合
在全场景智慧时代,用户对应用的需求早已不再局限于单一设备。鸿蒙 OS 以分布式软总线、一次开发多端部署的核心能力,构建了覆盖手机、平板、车机、智慧屏的全场景生态;而 Electron 凭借Web 技术栈快速开发桌面应用的特性,成为开发者打造跨平台桌面工具的首选框架。
但单独使用两者时,都会面临明显的短板:鸿蒙桌面应用开发门槛高,Web 生态兼容性弱;Electron 应用则缺乏多设备协同能力,无法接入鸿蒙的分布式硬件资源。因此,鸿蒙与 Electron 的融合开发成为破局关键 —— 既能用 HTML/CSS/JS 快速构建桌面交互界面,又能借助鸿蒙的分布式能力实现多设备联动,真正做到 "一套代码,多端赋能"。
本文将围绕鸿蒙与 Electron 的深度集成展开,从底层通信原理到上层应用开发,结合 3 个实战项目,提供可直接落地的技术方案。全文包含超 10 段核心代码、8 个官方资源链接,适合前端开发者、鸿蒙生态工程师学习参考,助力大家快速掌握跨端开发的核心技能。
一、技术底层:鸿蒙与 Electron 融合的核心原理
1.1 融合架构设计
鸿蒙与 Electron 的融合并非简单的 "移植",而是基于进程间通信(IPC)和分布式服务的架构整合,核心分为三层:
- 应用层:Electron 负责桌面端的 UI 渲染与交互逻辑,鸿蒙应用负责多设备的硬件调用与数据同步;
- 通信层:通过 WebSocket、鸿蒙分布式数据服务(DDS)实现跨设备、跨进程的数据传输;
- 硬件层:鸿蒙设备提供传感器、摄像头、蓝牙等硬件能力,Electron 桌面端作为控制中枢下发指令。
整体架构如下图所示:
plaintext
Electron桌面端(主控) ↓ ↑ WebSocket/DDS通信 鸿蒙设备集群(执行) - 手机:传感器数据采集 - 平板:大屏展示 - 智慧屏:音视频输出1.2 关键技术对比与选型
| 技术方案 | 适用场景 | 优势 | 局限性 |
|---|---|---|---|
| WebSocket 通信 | 局域网内设备协同 | 实时性高、开发成本低 | 依赖网络、不支持离线通信 |
| 鸿蒙分布式数据服务 | 跨设备数据共享 | 鸿蒙原生支持、离线同步 | 仅适用于鸿蒙设备、配置复杂 |
| Native 桥接(C++) | 高性能硬件调用 | 低延迟、高兼容性 | 开发门槛高、跨平台性差 |
选型建议:开发初期优先使用 WebSocket 实现快速验证;产品化阶段结合鸿蒙 DDS 提升稳定性与离线能力;高性能场景(如音视频处理)可采用 C++ Native 桥接方案。
1.3 开发环境前置要求
- 硬件:Windows/macOS 开发机(内存≥16GB)、鸿蒙设备(API 9+,支持开发者模式)
- 软件:
- DevEco Studio 5.0+:官方下载地址
- Node.js 18.x LTS:Node.js 官方下载
- Electron 28.x+:
npm install electron -g - 鸿蒙 SDK(API 9+):通过 DevEco Studio 自动安装
- 账号:华为开发者账号(完成实名认证,用于应用签名):华为开发者联盟
二、实战项目 1:基础通信 ——Electron 与鸿蒙设备的 WebSocket 双向交互
本项目实现最基础的跨设备通信能力:Electron 桌面端作为 WebSocket 服务端,鸿蒙设备作为客户端,完成指令下发与数据上传的双向交互。
2.1 项目结构搭建
plaintext
harmony-electron-demo/ ├── electron-main/ # Electron桌面端代码 │ ├── main.js # 主进程:WebSocket服务+窗口管理 │ ├── preload.js # 预加载脚本:安全通信桥 │ ├── renderer/ # 渲染进程:UI界面 │ │ ├── index.html │ │ ├── style.css │ │ └── renderer.js │ └── package.json └── harmony-device/ # 鸿蒙设备端代码 └── entry/ └── src/main/ets/ ├── MainAbility.ets # 鸿蒙应用入口:WebSocket客户端 └── pages/ └── Index.ets # 鸿蒙UI页面2.2 Electron 桌面端实现(服务端)
2.2.1 主进程代码(main.js)
主进程负责启动 WebSocket 服务、创建桌面窗口、处理设备通信逻辑。
javascript
运行
const { app, BrowserWindow, ipcMain } = require('electron'); const path = require('path'); const WebSocket = require('ws'); let mainWindow; let wss; // WebSocket服务实例 // 创建Electron窗口 function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, // 开启上下文隔离,保障安全 nodeIntegration: false // 禁用Node.js集成 } }); // 加载渲染进程页面 mainWindow.loadFile(path.join(__dirname, 'renderer/index.html')); // 开发阶段打开调试工具 mainWindow.webContents.openDevTools(); } // 启动WebSocket服务 function startWSServer() { wss = new WebSocket.Server({ port: 9000 }); console.log('WebSocket服务已启动:ws://localhost:9000'); // 监听设备连接 wss.on('connection', (ws) => { console.log('鸿蒙设备已连接'); // 向渲染进程发送连接状态 mainWindow.webContents.send('device-status', 'connected'); // 接收设备上传的数据 ws.on('message', (message) => { const data = JSON.parse(message.toString()); console.log('收到设备数据:', data); // 转发数据到渲染进程 mainWindow.webContents.send('device-data', data); }); // 监听连接关闭 ws.on('close', () => { console.log('鸿蒙设备已断开'); mainWindow.webContents.send('device-status', 'disconnected'); }); // 发送初始化指令 ws.send(JSON.stringify({ type: 'init', content: '欢迎连接桌面端' })); }); } // 监听渲染进程的指令下发请求 ipcMain.on('send-command', (event, command) => { if (wss && wss.clients.size > 0) { wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ type: 'command', data: command })); } }); } }); // 应用生命周期管理 app.whenReady().then(() => { createWindow(); startWSServer(); // 启动WebSocket服务 }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });2.2.2 预加载脚本(preload.js)
用于在主进程与渲染进程之间建立安全通信桥,避免直接暴露 Node.js API。
javascript
运行
const { contextBridge, ipcRenderer } = require('electron'); // 向渲染进程暴露安全API contextBridge.exposeInMainWorld('electronAPI', { // 接收设备状态 onDeviceStatus: (callback) => ipcRenderer.on('device-status', (event, status) => callback(status)), // 接收设备数据 onDeviceData: (callback) => ipcRenderer.on('device-data', (event, data) => callback(data)), // 下发指令到设备 sendCommand: (command) => ipcRenderer.send('send-command', command) });2.2.3 渲染进程代码(index.html + renderer.js)
html
预览
<!-- index.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>鸿蒙-Electron通信 Demo</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="container"> <h1>鸿蒙设备通信控制台</h1> <div class="status">设备状态:<span id="status">未连接</span></div> <div class="data-view">设备数据:<span id="data">无</span></div> <div class="command-input"> <input type="text" id="command" placeholder="输入指令发送到设备"> <button id="send-btn">发送指令</button> </div> </div> <script src="renderer.js"></script> </body> </html>javascript
运行
// renderer.js const statusEl = document.getElementById('status'); const dataEl = document.getElementById('data'); const commandInput = document.getElementById('command'); const sendBtn = document.getElementById('send-btn'); // 监听设备状态 window.electronAPI.onDeviceStatus((status) => { statusEl.textContent = status; statusEl.style.color = status === 'connected' ? 'green' : 'red'; }); // 监听设备数据 window.electronAPI.onDeviceData((data) => { dataEl.textContent = JSON.stringify(data); }); // 发送指令到设备 sendBtn.addEventListener('click', () => { const command = commandInput.value.trim(); if (command) { window.electronAPI.sendCommand(command); commandInput.value = ''; } });2.3 鸿蒙设备端实现(客户端)
鸿蒙设备端通过 WebSocket 连接桌面端,实现数据上传与指令接收。
2.3.1 MainAbility.ets(应用入口)
typescript
运行
import web_socket from '@ohos.net.webSocket'; import hilog from '@ohos.hilog'; let ws: web_socket.WebSocket | null = null; export default class MainAbility extends Ability { onCreate(want, launchParam) { hilog.info(0x0000, 'TEST_TAG', '%{public}s', 'Ability onCreate'); this.initWebSocket(); } // 初始化WebSocket连接 initWebSocket() { ws = web_socket.createWebSocket(); // 替换为桌面端的局域网IP const url = 'ws://192.168.1.105:9000'; ws.connect(url, (err, _) => { if (err) { hilog.error(0x0000, 'TEST_TAG', 'WebSocket连接失败:%{public}s', err.message); // 重试机制 setTimeout(() => this.initWebSocket(), 3000); return; } hilog.info(0x0000, 'TEST_TAG', 'WebSocket连接成功'); // 接收桌面端指令 ws.on('message', (message: string) => { const data = JSON.parse(message); hilog.info(0x0000, 'TEST_TAG', '收到桌面端指令:%{public}s', JSON.stringify(data)); // 转发指令到UI页面 globalThis.commandData = data; }); // 监听连接关闭 ws.on('close', () => { hilog.info(0x0000, 'TEST_TAG', 'WebSocket连接关闭'); setTimeout(() => this.initWebSocket(), 3000); }); }); } // 向桌面端发送数据 sendDataToDesktop(data: object) { if (ws && ws.readyState === web_socket.WebSocketState.OPEN) { ws.send(JSON.stringify(data), (err) => { if (err) { hilog.error(0x0000, 'TEST_TAG', '数据发送失败:%{public}s', err.message); } }); } } onDestroy() { hilog.info(0x0000, 'TEST_TAG', '%{public}s', 'Ability onDestroy'); if (ws) { ws.close(); } } }2.3.2 Index.ets(UI 页面)
typescript
运行
@Entry @Component struct Index { @State message: string = '设备数据上传 Demo' @State deviceData: string = '' @State command: string = '无' build() { Column() { Text(this.message) .fontSize(30) .fontWeight(FontWeight.Bold) .margin(20) Text(`接收的指令:${this.command}`) .fontSize(20) .margin(10) Button('上传设备信息') .onClick(() => { const data = { deviceName: 'HarmonyOS Phone', time: new Date().toLocaleString(), battery: '85%' }; this.deviceData = JSON.stringify(data); // 调用Ability的方法发送数据 const ability = getContext(this) as Ability; (ability as any).sendDataToDesktop(data); }) .margin(20) Text(`上传的数据:${this.deviceData}`) .fontSize(16) .margin(10) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } // 监听全局指令数据变化 aboutToAppear() { setInterval(() => { if (globalThis.commandData) { this.command = JSON.stringify(globalThis.commandData); } }, 1000); } }2.4 运行测试步骤
- 启动 Electron 桌面端:
bash
运行
cd electron-main npm install npm start - 配置鸿蒙设备端:修改
MainAbility.ets中的桌面端 IP 为实际局域网 IP; - 运行鸿蒙应用:在 DevEco Studio 中连接鸿蒙设备,点击 "运行" 按钮;
- 功能验证:
- 设备端点击 "上传设备信息",桌面端接收并显示数据;
- 桌面端输入指令并发送,设备端接收并显示指令内容。
三、实战项目 2:进阶应用 —— 鸿蒙传感器数据在 Electron 桌面端可视化
本项目基于基础通信能力,实现鸿蒙设备传感器数据采集+Electron 桌面端可视化展示,核心使用鸿蒙的加速度传感器 API和 Electron 的Chart.js图表库
。
3.1 鸿蒙设备端:加速度传感器数据采集
在鸿蒙项目中添加传感器权限与数据采集逻辑。
3.1.1 添加权限配置(module.json5)
在module.json5的reqPermissions中添加传感器权限:
json5
{ "module": { "reqPermissions": [ { "name": "ohos.permission.ACCELEROMETER" // 加速度传感器权限 } ] } }3.1.2 传感器数据采集代码(Index.ets)
typescript
运行
import sensor from '@ohos.sensor'; import { BusinessError } from '@ohos.base'; @Entry @Component struct Index { @State message: string = '加速度传感器数据采集' @State x: number = 0 @State y: number = 0 @State z: number = 0 private accelerometerListener: sensor.AccelerometerResponse | null = null build() { Column() { Text(this.message) .fontSize(30) .fontWeight(FontWeight.Bold) .margin(20) Text(`X轴:${this.x.toFixed(2)} m/s²`) .fontSize(20) .margin(5) Text(`Y轴:${this.y.toFixed(2)} m/s²`) .fontSize(20) .margin(5) Text(`Z轴:${this.z.toFixed(2)} m/s²`) .fontSize(20) .margin(5) Button('开始采集') .onClick(() => this.startCollect()) .margin(10) Button('停止采集') .onClick(() => this.stopCollect()) .margin(10) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } // 开始采集传感器数据 startCollect() { this.accelerometerListener = (data) => { this.x = data.x; this.y = data.y; this.z = data.z; // 每100ms上传一次数据到桌面端 const ability = getContext(this) as Ability; (ability as any).sendDataToDesktop({ type: 'accelerometer', x: data.x, y: data.y, z: data.z, time: Date.now() }); } try { sensor.on(sensor.SensorTypeId.ACCELEROMETER, this.accelerometerListener, { interval: sensor.SensorInterval.SENSOR_INTERVAL_100MS }); } catch (err) { console.error(`传感器监听失败:${(err as BusinessError).message}`); } } // 停止采集 stopCollect() { if (this.accelerometerListener) { sensor.off(sensor.SensorTypeId.ACCELEROMETER, this.accelerometerListener); this.accelerometerListener = null; } } aboutToDisappear() { this.stopCollect(); } }3.2 Electron 桌面端:数据可视化展示
在 Electron 渲染进程中集成 Chart.js,实现传感器数据的实时折线图展示。
3.2.1 安装 Chart.js
bash
运行
cd electron-main npm install chart.js --save3.2.2 渲染进程代码修改(renderer.js)
javascript
运行
import Chart from 'chart.js/auto'; const statusEl = document.getElementById('status'); const dataEl = document.getElementById('data'); const commandInput = document.getElementById('command'); const sendBtn = document.getElementById('send-btn'); // 初始化图表 const ctx = document.getElementById('sensorChart').getContext('2d'); const sensorChart = new Chart(ctx, { type: 'line', data: { labels: [], // 时间轴 datasets: [ { label: 'X轴加速度', data: [], borderColor: 'red', tension: 0.1 }, { label: 'Y轴加速度', data: [], borderColor: 'green', tension: 0.1 }, { label: 'Z轴加速度', data: [], borderColor: 'blue', tension: 0.1 } ] }, options: { responsive: true, scales: { y: { title: { display: true, text: '加速度 (m/s²)' } }, x: { title: { display: true, text: '时间' } } } } }); // 监听设备数据并更新图表 window.electronAPI.onDeviceData((data) => { if (data.type === 'accelerometer') { // 限制数据点数量为50个 if (sensorChart.data.labels.length > 50) { sensorChart.data.labels.shift(); sensorChart.data.datasets.forEach(dataset => dataset.data.shift()); } // 添加新数据 sensorChart.data.labels.push(new Date(data.time).toLocaleTimeString()); sensorChart.data.datasets[0].data.push(data.x); sensorChart.data.datasets[1].data.push(data.y); sensorChart.data.datasets[2].data.push(data.z); sensorChart.update(); } dataEl.textContent = JSON.stringify(data); }); // 原有代码保持不变 window.electronAPI.onDeviceStatus((status) => { statusEl.textContent = status; statusEl.style.color = status === 'connected' ? 'green' : 'red'; }); sendBtn.addEventListener('click', () => { const command = commandInput.value.trim(); if (command) { window.electronAPI.sendCommand(command); commandInput.value = ''; } });3.2.3 修改 HTML 页面(index.html)
添加图表容器:
html
预览
<div class="chart-container"> <canvas id="sensorChart"></canvas> </div>添加 CSS 样式:
css
.chart-container { width: 90%; height: 300px; margin: 20px auto; }3.3 功能验证
- 启动 Electron 桌面端与鸿蒙应用;
- 鸿蒙设备端点击 "开始采集",手持设备晃动;
- 桌面端实时显示加速度数据的折线图,X/Y/Z 轴数据随设备运动动态变化。
四、实战项目 3:高级特性 —— 鸿蒙原子化服务与 Electron 应用的联动
鸿蒙原子化服务是免安装、即用即走的轻量化应用形态,本项目将 Electron 应用适配为鸿蒙原子化服务的 "控制中枢",实现服务卡片触发 Electron 应用启动、Electron 应用控制原子化服务运行的联动效果。
4.1 核心适配逻辑
- Electron 应用打包:将 Electron 桌面端打包为鸿蒙 PC 可执行文件;
- 原子化服务开发:开发鸿蒙服务卡片,点击卡片触发 Electron 应用启动;
- 跨应用通信:通过鸿蒙分布式任务调度实现原子化服务与 Electron 应用的通信。
4.2 关键代码实现
4.2.1 Electron 应用打包(package.json)
使用electron-builder打包为鸿蒙 PC 支持的格式:
json
{ "scripts": { "build:harmony": "electron-builder --linux --arm64" }, "build": { "appId": "com.example.harmonyelectron", "productName": "HarmonyElectronDemo", "linux": { "target": [ { "target": "AppImage", "arch": ["arm64"] } ] } } }执行打包命令:
bash
运行
npm run build:harmony4.2.2 鸿蒙原子化服务卡片代码(CardAbility.ets)
typescript
运行
import card from '@ohos.service.card'; import hilog from '@ohos.hilog'; import Want from '@ohos.app.ability.Want'; export default class CardAbility extends card.CardExtensionAbility { onCreate(want: Want) { hilog.info(0x0000, 'TEST_TAG', '卡片创建'); } onUpdate(formId: string) { // 更新卡片数据 const formData = { title: 'Electron控制卡片', content: '点击启动桌面应用' }; card.updateForm(formId, formData).then(() => { hilog.info(0x0000, 'TEST_TAG', '卡片更新成功'); }); } // 点击卡片触发事件 onTriggerForm(formId: string, message: string) { // 启动Electron应用 const want: Want = { bundleName: 'com.example.harmonyelectron', abilityName: 'MainAbility', action: 'ohos.want.action.startApplication' }; this.context.startAbility(want).then(() => { hilog.info(0x0000, 'TEST_TAG', '启动Electron应用成功'); }); } }4.3 部署与验证
- 将打包后的 Electron 应用安装到鸿蒙 PC 设备;
- 在鸿蒙设备桌面添加原子化服务卡片;
- 点击卡片,自动启动 Electron 应用;
- Electron 应用下发指令,控制鸿蒙原子化服务执行特定任务(如播放音乐、显示通知)。
五、性能优化与常见问题解决方案
5.1 性能优化策略
- 通信优化:
- 数据压缩:使用 gzip 压缩传输数据,减少网络开销;
- 批量发送:传感器数据采用批量上传,降低通信频率。
- Electron 优化:
- 禁用硬件加速:
app.disableHardwareAcceleration(),避免鸿蒙 PC 渲染异常; - 进程隔离:将耗时任务放在独立进程,避免阻塞主进程。
- 禁用硬件加速:
- 鸿蒙端优化:
- 传感器采样频率:根据需求调整,非必要不使用高频采样;
- 后台运行:配置鸿蒙应用后台运行权限,避免被系统杀死。
5.2 常见问题解决方案
| 问题现象 | 原因分析 | 解决方案 |
|---|---|---|
| WebSocket 连接失败 | 1. 设备不在同一局域网;2. 端口被占用 | 1. 检查网络配置;2. 更换端口(如 9001);3. 关闭防火墙 |
| 传感器数据采集失败 | 未申请权限或权限被拒绝 | 1. 在 module.json5 中添加权限;2. 引导用户手动授予权限 |
| Electron 应用在鸿蒙 PC 无法启动 | 打包架构不匹配 | 使用--arm64参数打包,适配鸿蒙 PC 的 ARM 架构 |
| 原子化服务卡片不显示 | 卡片配置错误 | 检查 module.json5 中的extensionAbilities配置,确保cardSize合法 |
六、生态资源与未来展望
6.1 核心学习资源
- 鸿蒙官方文档:HarmonyOS 开发者文档中心
- Electron 官方文档:Electron API Reference
- OpenHarmony SIG Electron 项目:Gitee 仓库(鸿蒙官方维护的 Electron 适配项目)
- 鸿蒙传感器开发指南:传感器 API 文档
6.2 未来展望
- 官方适配增强:华为 OpenHarmony 社区正在推进 Electron 原生适配,未来将提供更完善的工具链与 API;
- 能力深度融合:Electron 应用将可直接调用鸿蒙的分布式能力,无需额外的通信层开发;
- 跨端生态统一:Web 技术栈将成为鸿蒙跨端开发的核心之一,Electron 作为 Web 桌面应用的代表,将在鸿蒙生态中发挥更大作用。
结语
鸿蒙与 Electron 的融合开发,为跨端应用开发提供了全新的思路 —— 既保留了 Web 技术栈的高效开发优势,又能充分利用鸿蒙的全场景能力。本文通过 3 个实战项目,从基础通信到高级联动,完整覆盖了鸿蒙 + Electron 开发的核心流程。
随着鸿蒙生态的不断发展,这种跨端开发模式将在更多场景中落地,助力开发者打造真正的全场景智慧应用。希望本文能为大家的学习与实践提供帮助,让我们一起探索跨端开发的无限可能!