在跨端开发领域,Electron 凭借其 “HTML+CSS+JavaScript” 的技术栈和跨 Windows、macOS、Linux 三大桌面平台的能力,成为前端开发者开发桌面应用的首选方案之一。而鸿蒙(HarmonyOS)作为华为推出的分布式操作系统,以 “一次开发,多端部署” 为核心,覆盖手机、平板、智慧屏、穿戴设备等全场景终端。将鸿蒙与 Electron 结合,既能利用 Electron 成熟的桌面开发生态,又能借力鸿蒙的分布式能力,为跨端应用开发开辟新路径。本文将深入探讨鸿蒙与 Electron 的融合思路,并通过代码案例展示具体实现方式。

一、鸿蒙与 Electron 融合的技术背景

1. Electron 的核心优势

Electron 本质上是将 Chromium 浏览器和 Node.js 打包在一起,使得开发者可以用前端技术开发桌面应用。其核心优势在于:

  • 技术栈统一:前端开发者无需学习 C++、Objective-C 等原生语言,直接使用 HTML/CSS/JS 开发。
  • 生态丰富:依托 Node.js 和前端生态,海量的 npm 包可以直接复用。
  • 跨平台便捷:一行命令即可打包成 Windows、macOS、Linux 的安装包。

2. 鸿蒙的全场景能力

鸿蒙 OS 采用分布式架构,核心特性包括:

  • 分布式数据管理:多设备间数据实时同步,实现 “数据一处修改,多端同步更新”。
  • 分布式任务调度:应用可根据设备能力,将任务分发到不同设备执行。
  • 多端部署:鸿蒙应用可通过自适应布局和组件复用,运行在不同尺寸的鸿蒙设备上。

3. 融合的核心思路

鸿蒙与 Electron 的融合主要分为两种场景:

  • 场景一:在 Electron 桌面应用中集成鸿蒙 SDK,实现与鸿蒙设备的互联互通(如桌面应用控制鸿蒙智慧屏、穿戴设备)。
  • 场景二:将 Electron 应用迁移 / 适配到鸿蒙系统(鸿蒙桌面版),利用 Electron 的生态优势开发鸿蒙桌面应用。

本文主要聚焦场景一,通过代码案例实现 Electron 桌面应用与鸿蒙设备的简单交互。

二、环境准备

在开始编码前,需要准备以下开发环境:

  1. Electron 开发环境:Node.js(建议 16 + 版本)、npm/yarn、Electron CLI(electronelectron-forge)。
  2. 鸿蒙开发环境:DevEco Studio(最新版本)、鸿蒙 SDK(API 9+,支持分布式能力)。
  3. 鸿蒙设备:一台已联网的鸿蒙设备(如鸿蒙手机、平板),并开启开发者模式。

环境搭建命令(Electron 侧)

bash

运行

# 初始化Node.js项目
npm init -y

# 安装Electron依赖
npm install electron --save-dev

# 安装electron-forge(可选,用于打包和调试)
npm install @electron-forge/cli --save-dev
npx electron-forge import

三、代码案例:Electron 应用与鸿蒙设备的互联互通

本案例实现一个简单的 Electron 桌面应用,该应用可以向鸿蒙设备发送消息,并接收鸿蒙设备的反馈。核心技术点包括:鸿蒙分布式数据服务(DDS)Electron 的网络通信(WebSocket)。

步骤 1:鸿蒙端开发(消息收发服务)

鸿蒙端使用Stage 模型开发,通过 WebSocket 与 Electron 应用通信,同时利用鸿蒙的分布式能力实现设备间消息同步。

1.1 鸿蒙端配置权限

entry/src/main/module.json5中添加网络权限:

json5

{
  "module": {
    // 其他配置...
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}
1.2 鸿蒙端 WebSocket 客户端代码

entry/src/main/ets/pages/Index.ets中编写核心代码:

typescript

运行

@Entry
@Component
struct Index {
  @State message: string = '等待Electron消息...'
  private webSocket: WebSocket | null = null

  // 页面加载时连接WebSocket(Electron应用的WebSocket服务)
  aboutToAppear() {
    this.connectWebSocket()
  }

  // 连接WebSocket
  connectWebSocket() {
    this.webSocket = new WebSocket('ws://192.168.1.100:8080') // 替换为Electron的IP和端口

    // 连接成功回调
    this.webSocket.onopen = () => {
      console.log('WebSocket连接成功')
      this.webSocket?.send('鸿蒙设备已连接')
    }

    // 接收消息回调
    this.webSocket.onmessage = (event) => {
      const receivedMsg = event.data as string
      this.message = `收到Electron消息:${receivedMsg}`
      // 回复消息
      this.webSocket?.send(`已收到:${receivedMsg}`)
    }

    // 连接关闭回调
    this.webSocket.onclose = () => {
      console.log('WebSocket连接关闭')
      this.message = '连接已关闭,正在重连...'
      // 重连机制
      setTimeout(() => this.connectWebSocket(), 3000)
    }

    // 错误回调
    this.webSocket.onerror = (error) => {
      console.error('WebSocket错误:', error)
      this.message = '连接失败'
    }
  }

  build() {
    Column() {
      Text(this.message)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 100 })
        .textAlign(TextAlign.Center)
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.White)
  }
}

步骤 2:Electron 端开发(桌面应用 + WebSocket 服务)

Electron 端分为主进程渲染进程:主进程启动 WebSocket 服务,处理与鸿蒙设备的通信;渲染进程负责 UI 展示和用户交互。

2.1 Electron 主进程代码(main.js)

主进程启动 WebSocket 服务,并实现与渲染进程的 IPC 通信:

javascript

运行

const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const WebSocket = require('ws'); // 安装:npm install ws --save

// 保存窗口实例
let mainWindow;
// WebSocket服务器实例
let wss;

// 创建窗口
function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      nodeIntegration: true, // 开发环境开启,生产环境建议关闭
      contextIsolation: false // 开发环境关闭,生产环境建议开启
    }
  });

  // 加载本地HTML文件
  mainWindow.loadFile('index.html');

  // 打开开发者工具(开发环境)
  mainWindow.webContents.openDevTools();
}

// 启动WebSocket服务
function startWebSocketServer() {
  wss = new WebSocket.Server({ port: 8080 });
  console.log('WebSocket服务已启动,端口:8080');

  // 监听新连接
  wss.on('connection', (ws) => {
    console.log('鸿蒙设备已连接');

    // 接收鸿蒙设备的消息
    ws.on('message', (message) => {
      const msg = message.toString();
      console.log('收到鸿蒙设备消息:', msg);
      // 向渲染进程发送消息(用于UI展示)
      mainWindow.webContents.send('device-message', msg);
    });

    // 连接关闭
    ws.on('close', () => {
      console.log('鸿蒙设备已断开连接');
      mainWindow.webContents.send('device-status', 'disconnected');
    });

    // 错误处理
    ws.on('error', (error) => {
      console.error('WebSocket错误:', error);
    });

    // 保存WebSocket连接,供渲染进程调用
    global.harmonyWs = ws;
  });
}

// 应用就绪后创建窗口并启动服务
app.whenReady().then(() => {
  createWindow();
  startWebSocketServer();

  // 监听渲染进程的消息发送请求
  ipcMain.on('send-message-to-device', (event, msg) => {
    if (global.harmonyWs) {
      global.harmonyWs.send(msg);
      console.log('向鸿蒙设备发送消息:', msg);
    } else {
      event.reply('send-failed', '未连接鸿蒙设备');
    }
  });

  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

// 关闭所有窗口时退出应用(macOS除外)
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit();
});
2.2 Electron 预加载脚本(preload.js)

预加载脚本用于渲染进程和主进程的安全通信(可选,这里简化处理):

javascript

运行

const { ipcRenderer } = require('electron');

// 暴露API给渲染进程
window.electronAPI = {
  sendMessageToDevice: (msg) => ipcRenderer.send('send-message-to-device', msg),
  onDeviceMessage: (callback) => ipcRenderer.on('device-message', (event, msg) => callback(msg)),
  onSendFailed: (callback) => ipcRenderer.on('send-failed', (event, msg) => callback(msg)),
  onDeviceStatus: (callback) => ipcRenderer.on('device-status', (event, status) => callback(status))
};
2.3 Electron 渲染进程代码(index.html)

渲染进程负责 UI 展示,提供输入框和按钮发送消息:

html

预览

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Electron + 鸿蒙交互示例</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      padding: 20px;
      background-color: #f5f5f5;
    }
    .container {
      max-width: 600px;
      margin: 0 auto;
      background: white;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 0 10px rgba(0,0,0,0.1);
    }
    #messageInput {
      width: 70%;
      padding: 10px;
      font-size: 16px;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    #sendBtn {
      padding: 10px 20px;
      font-size: 16px;
      background-color: #007bff;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      margin-left: 10px;
    }
    #sendBtn:hover {
      background-color: #0056b3;
    }
    #messageList {
      margin-top: 20px;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 4px;
      height: 300px;
      overflow-y: auto;
    }
    .message-item {
      margin: 5px 0;
      padding: 8px;
      border-radius: 4px;
    }
    .electron-msg {
      background-color: #e6f7ff;
    }
    .device-msg {
      background-color: #f6ffed;
    }
    .error-msg {
      background-color: #fff2f0;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>Electron ↔ 鸿蒙设备交互</h1>
    <div>
      <input type="text" id="messageInput" placeholder="请输入要发送的消息...">
      <button id="sendBtn">发送到鸿蒙设备</button>
    </div>
    <div id="messageList"></div>
  </div>

  <script>
    // 获取DOM元素
    const messageInput = document.getElementById('messageInput');
    const sendBtn = document.getElementById('sendBtn');
    const messageList = document.getElementById('messageList');

    // 添加消息到列表
    function addMessage(text, type) {
      const item = document.createElement('div');
      item.className = `message-item ${type}`;
      item.textContent = text;
      messageList.appendChild(item);
      // 滚动到底部
      messageList.scrollTop = messageList.scrollHeight;
    }

    // 发送消息按钮点击事件
    sendBtn.addEventListener('click', () => {
      const msg = messageInput.value.trim();
      if (!msg) return;
      // 发送消息到主进程
      window.electronAPI.sendMessageToDevice(msg);
      // 展示发送的消息
      addMessage(`Electron:${msg}`, 'electron-msg');
      // 清空输入框
      messageInput.value = '';
    });

    // 监听鸿蒙设备的消息
    window.electronAPI.onDeviceMessage((msg) => {
      addMessage(`鸿蒙设备:${msg}`, 'device-msg');
    });

    // 监听发送失败的回调
    window.electronAPI.onSendFailed((msg) => {
      addMessage(`错误:${msg}`, 'error-msg');
    });

    // 监听设备连接状态
    window.electronAPI.onDeviceStatus((status) => {
      addMessage(`设备状态:${status === 'disconnected' ? '已断开' : '已连接'}`, 'error-msg');
    });
  </script>
</body>
</html>

步骤 3:运行和测试

  1. 启动 Electron 应用:在项目根目录执行命令:

    bash

    运行

    # 方式1:直接运行
    npx electron .
    
    # 方式2:使用electron-forge运行
    npm run start
    

    此时 Electron 应用会启动,WebSocket 服务也会在 8080 端口监听。

  2. 运行鸿蒙应用:在 DevEco Studio 中,将鸿蒙应用运行到真机或模拟器(确保设备与 Electron 应用在同一局域网,且 IP 地址正确)。

  3. 测试交互

    • 在 Electron 应用的输入框中输入消息,点击 “发送到鸿蒙设备”,鸿蒙设备会收到消息并显示。
    • 鸿蒙设备会自动回复消息,Electron 应用会接收并展示回复内容。

四、进阶方向:融合鸿蒙分布式能力

上述案例实现了基础的消息交互,在此基础上,还可以融合鸿蒙的分布式能力,实现更复杂的场景:

  1. 分布式数据同步:将 Electron 应用的本地数据与鸿蒙设备的分布式数据仓同步,实现 “桌面修改,鸿蒙设备同步更新”。
  2. 分布式任务调度:在 Electron 桌面应用中触发鸿蒙设备的任务(如鸿蒙智慧屏播放视频、鸿蒙手表显示通知)。
  3. 鸿蒙桌面版适配:将 Electron 应用打包为鸿蒙桌面版的安装包,利用 Electron 生态开发鸿蒙桌面应用。

五、总结

鸿蒙与 Electron 的融合,是前端跨端开发与鸿蒙全场景生态的一次有效结合。通过本文的代码案例,我们实现了 Electron 桌面应用与鸿蒙设备的 WebSocket 通信,验证了两者融合的可行性。对于开发者而言,既可以利用 Electron 的前端生态快速开发桌面应用,又能借助鸿蒙的分布式能力拓展应用的全场景覆盖范围。

随着鸿蒙系统的不断发展,尤其是鸿蒙桌面版的普及,Electron 与鸿蒙的融合场景将更加丰富。开发者可以基于本文的思路,探索更多跨端交互的可能性,打造更强大的全场景应用。

编辑分享

欢迎大家加入[开源鸿蒙跨平台开发者社区](https://openharmonycrossplatform.csdn.net),一起共建开源鸿蒙跨平台生态。

Logo

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

更多推荐