前言

在跨端开发领域,Electron 凭借 “一次编写、多端运行” 的特性占据重要地位,其基于 Chromium 和 Node.js 的架构可快速将 Web 应用打包为 Windows、macOS、Linux 桌面应用。而鸿蒙系统(HarmonyOS)作为面向全场景的分布式操作系统,正逐步完善鸿蒙 PC、智慧屏等桌面端设备生态。将 Electron 与鸿蒙 PC 结合,既能复用 Web 技术栈的海量资源,又能借助鸿蒙的分布式能力实现 “跨设备无缝流转”,为开发者提供更灵活的全场景应用开发方案,尤其能满足鸿蒙 PC 用户对优质桌面应用的迫切需求。

本文面向有 Web 或桌面开发基础的开发者,从技术背景、环境搭建、核心功能开发到场景落地,全程附代码示例与官方文档链接,助力快速上手鸿蒙 PC Electron 开发。

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

1.1 为什么需要鸿蒙 PC + Electron?

  • 技术复用:Electron 基于 Web 技术栈(HTML/CSS/JavaScript),开发者无需学习全新语言即可开发鸿蒙 PC 应用,降低迁移成本。
  • 跨端能力互补:Electron 擅长桌面端应用开发,鸿蒙擅长分布式跨设备协同,二者结合可实现 “鸿蒙 PC 端功能 + 多设备流转” 的全场景体验(如鸿蒙 PC 端编辑文档,智慧屏端展示、手机端审批)。
  • 生态适配需求:鸿蒙 PC(如华为 MateBook X Pro 2024 款鸿蒙版)正处于生态快速建设阶段,急需更多优质桌面应用,Electron 可将现有成熟桌面应用快速适配鸿蒙 PC,加速鸿蒙 PC 生态完善。

1.2 核心技术原理

鸿蒙系统通过方舟引擎(Ark Engine)支持 Electron 应用在鸿蒙 PC 上稳定运行,核心逻辑如下:

  • Electron 应用的 Chromium 内核与鸿蒙 PC 的图形渲染框架深度适配,确保界面高清显示、操作流畅响应;
  • Electron 的 Node.js 层与鸿蒙 PC 的系统 API 桥接,实现文件操作、设备调用等原生能力适配;
  • 借助鸿蒙的分布式软总线,鸿蒙 PC 上的 Electron 应用可调用其他鸿蒙设备的资源(如摄像头、扬声器),也可被其他设备调用自身资源。

1.3 官方资源参考

  • 鸿蒙 PC 开发官网:HarmonyOS for PC 开发指南
  • Electron 官方文档:Electron 官方指南
  • 鸿蒙与 Electron 适配说明:HarmonyOS 第三方框架适配文档

二、鸿蒙 PC Electron 开发环境搭建(附代码与操作步骤)

环境搭建分为 3 个核心步骤:基础环境(Node.js + Electron)、鸿蒙 PC 开发环境(DevEco Studio)、工程初始化与依赖配置。全程基于 Windows 11 系统演示,macOS/Linux 步骤类似,最终均适配鸿蒙 PC 设备。

2.1 基础环境准备(Node.js + Electron)

2.1.1 安装 Node.js

Electron 依赖 Node.js 环境,需安装 Node.js 16.x LTS 版本(经测试与鸿蒙 PC 适配最佳,高版本可能存在兼容性问题)。

  • 下载地址:Node.js 16.20.2 官网下载
  • 安装后验证:打开命令行(CMD 或 PowerShell),执行以下命令,输出版本号即安装成功:
node -v  # 需输出 v16.20.2
npm -v   # 需输出 8.19.4(Node.js 16.x 默认版本)
2.1.2 安装 Electron

通过 npm 全局安装 Electron,指定版本为 22.3.2(与鸿蒙 PC 方舟引擎适配的稳定版本):

# 全局安装Electron
npm install -g electron@22.3.2
# 验证安装
electron -v  # 需输出 v22.3.2

2.2 鸿蒙 PC 开发环境配置(DevEco Studio)

鸿蒙 PC 应用的编译、打包与设备调试需通过 DevEco Studio 完成,需安装 DevEco Studio 4.0 及以上版本。

  • 下载地址:DevEco Studio 官网下载
  • 安装步骤:
    1. 双击安装包,选择 “自定义安装”,勾选 “HarmonyOS SDK for PC”(鸿蒙 PC 开发必需);
    2. 安装完成后,打开 DevEco Studio,自动下载鸿蒙 PC 端 SDK(版本选择 3.2.100 及以上);
    3. 配置 SDK 路径:进入「File > Settings > Appearance & Behavior > System Settings > HarmonyOS SDK」,确认 “PC” 选项卡下的 SDK 已全部下载。
  • 验证环境:
    1. 打开 DevEco Studio,创建一个 “Empty Ability” 项目,模板选择 “PC”;
    2. 连接鸿蒙 PC 设备或启动鸿蒙 PC 模拟器(需在「Tools > Device Manager」中申请);
    3. 点击 “Run” 按钮,若项目能正常运行(显示默认页面),则鸿蒙 PC 开发环境配置成功。

2.3 鸿蒙 PC Electron 工程初始化(附代码)

2.3.1 创建 Electron 基础工程

新建文件夹(如HarmonyElectronDemo),打开命令行进入该文件夹,执行以下命令初始化 Electron 工程(适配鸿蒙 PC 运行):

bash

运行

# 初始化package.json(一路回车默认配置即可)
npm init -y
# 安装本地Electron依赖(确保与全局版本一致,适配鸿蒙PC)
npm install electron@22.3.2 --save-dev

在工程根目录创建 3 个核心文件:

  • main.js:Electron 主进程文件(控制应用生命周期、创建窗口,适配鸿蒙 PC 窗口规范);
  • index.html:应用界面文件(Web 端页面,适配鸿蒙 PC 屏幕分辨率);
  • preload.js:主进程与渲染进程的通信桥接文件(适配鸿蒙 PC 跨进程通信机制)。
2.3.2 核心文件代码实现

(1)main.js(Electron 主进程,适配鸿蒙 PC 窗口特性)

// 引入Electron核心模块
const { app, BrowserWindow } = require('electron');
const path = require('path');

// 避免垃圾回收导致窗口被销毁
let mainWindow;

// 创建窗口函数(适配鸿蒙PC窗口尺寸与显示特性)
function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,          // 适配鸿蒙PC常见屏幕分辨率
    height: 600,         // 适配鸿蒙PC窗口交互逻辑
    webPreferences: {
      // 配置预加载脚本(用于主进程与渲染进程通信)
      preload: path.join(__dirname, 'preload.js'),
      // 启用Node.js环境(鸿蒙PC端需开启)
      nodeIntegration: true,
      contextIsolation: false  // 关闭上下文隔离(适配鸿蒙PC API调用)
    }
  });

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

  // 打开开发者工具(调试用,发布时需注释)
  mainWindow.webContents.openDevTools();

  // 窗口关闭事件
  mainWindow.on('closed', () => {
    mainWindow = null;
  });
}

// 应用就绪后创建窗口(适配鸿蒙PC应用启动机制)
app.whenReady().then(() => {
  createWindow();

  // 适配macOS(窗口关闭后重新打开)
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

// 所有窗口关闭后退出应用(Windows/Linux/鸿蒙PC)
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit();
});

(2)preload.js(通信桥接,适配鸿蒙 PC 跨进程通信)

// 暴露Electron的ipcRenderer到渲染进程(用于跨进程通信,适配鸿蒙PC通信规范)
window.ipcRenderer = require('electron').ipcRenderer;

(3)index.html(应用界面,适配鸿蒙 PC 显示效果)

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>鸿蒙PC Electron Demo</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      text-align: center;
      padding-top: 50px;
      /* 适配鸿蒙PC默认字体与显示密度 */
    }
    #deviceInfo {
      margin-top: 30px;
      color: #333;
      font-size: 16px;
    }
  </style>
</head>
<body>
  <h1>Hello 鸿蒙PC Electron!</h1>
  <button id="getDeviceBtn">获取鸿蒙PC设备信息</button>
  <div id="deviceInfo"></div>

  <script>
    // 监听按钮点击事件
    document.getElementById('getDeviceBtn').addEventListener('click', () => {
      // 后续章节将通过鸿蒙PC API获取设备信息,此处先占位
      document.getElementById('deviceInfo').innerText = '待获取鸿蒙PC设备信息...';
    });
  </script>
</body>
</html>
2.3.3 配置工程运行脚本

修改package.json,添加scripts字段,用于启动适配鸿蒙 PC 的 Electron 应用:

{
  "name": "harmony-pc-electron-demo",
  "version": "1.0.0",
  "main": "main.js",  // 指定主进程文件
  "scripts": {
    "start": "electron ."  // 启动命令(适配鸿蒙PC运行)
  },
  "devDependencies": {
    "electron": "^22.3.2"
  }
}
2.3.4 测试 Electron 工程(适配鸿蒙 PC 预览)

在命令行执行以下命令,若能弹出窗口并显示 “Hello 鸿蒙 PC Electron!”,则基础工程搭建成功,可后续对接鸿蒙 PC 设备:

npm run start

2.4 鸿蒙 PC 端工程配置(对接 Electron)

打开 DevEco Studio,创建一个 “Empty Ability” 项目,项目名称为HarmonyElectronHost,模板选择 “PC”(明确适配鸿蒙 PC),包名自定义(如com.example.harmonypcelectronhost)。

  1. 在鸿蒙 PC 工程的main_pages.json中添加 Electron 应用的启动页面配置:
{
  "src": [
    "main_pages/Index",
    {
      "src": "electron/ElectronPage",
      "window": {
        "designWidth": 800,  // 适配鸿蒙PC窗口设计宽度
        "autoDesignWidth": true
      }
    }
  ]
}
  1. src/main/electron目录下创建ElectronPage.ets文件,用于在鸿蒙 PC 上加载 Electron 应用:
import web_webview from '@ohos.web.webview';
import router from '@ohos.router';

@Entry
@Component
struct ElectronPage {
  build() {
    Column({ space: 10 }) {
      // 鸿蒙PC WebView组件:加载Electron应用的本地HTML
      Web({
        src: $rawfile('index.html'),  // 需将Electron工程的index.html放入鸿蒙PC工程的rawfile目录
        controller: new web_webview.WebViewController()
      })
      .width('100%')
      .height('90%')  // 适配鸿蒙PC页面布局比例

      // 返回按钮(适配鸿蒙PC交互逻辑)
      Button('返回首页')
        .width(150)
        .height(40)
        .onClick(() => {
          router.back();
        })
    }
    .width('100%')
    .height('100%')
  }
}
  1. 资源复制:将 Electron 工程中的index.htmlpreload.js复制到鸿蒙 PC 工程的src/main/rawfile目录(若没有rawfile目录,需手动创建)。

  2. 测试鸿蒙 PC 对接:

    • 启动鸿蒙 PC 模拟器或连接真实鸿蒙 PC 设备;
    • 点击 DevEco Studio 的 “Run” 按钮,进入ElectronPage页面,若能显示 Electron 应用的界面,则鸿蒙 PC 端配置成功。

2.5 环境搭建常见问题解决(针对鸿蒙 PC 场景)

问题现象 解决方案 参考链接
Electron 启动报错 “Cannot find module 'electron'” 1. 检查 Node.js 版本是否为 16.x(鸿蒙 PC 适配版本);2. 执行npm install重新安装依赖;3. 全局安装 Electron:npm install -g electron@22.3.2 Electron 安装问题排查
鸿蒙 PC WebView 加载 HTML 报错 “File not found” 1. 确认 HTML 文件路径是否正确;2. 检查rawfile目录是否在鸿蒙 PC 工程的src/main下;3. 清理工程缓存:「Build > Clean Project」 鸿蒙 WebView 资源加载指南
DevEco Studio 无法识别鸿蒙 PC 设备 1. 安装鸿蒙 PC 设备驱动:鸿蒙设备驱动下载;2. 开启鸿蒙 PC “开发者模式” 并允许 USB 调试 鸿蒙 PC 设备连接指南

三、鸿蒙 PC Electron 核心功能开发(多代码示例)

本节聚焦 3 个核心功能:鸿蒙 PC 设备信息获取、Electron 与鸿蒙 PC 的跨进程通信、分布式设备资源调用(鸿蒙 PC 为核心终端),每个功能均附完整代码与调试步骤。

3.1 功能 1:鸿蒙 PC 设备信息获取(Electron 调用鸿蒙 PC API)

通过鸿蒙的deviceInfo模块获取鸿蒙 PC 的设备型号、系统版本等信息,并在 Electron 界面展示。

3.1.1 鸿蒙 PC 端代码(能力封装)

在鸿蒙 PC 工程的src/main/ets/utils目录下创建DeviceInfoUtil.ets,封装鸿蒙 PC 设备信息获取方法:

import deviceInfo from '@ohos.device.deviceInfo';

/**
 * 鸿蒙PC设备信息工具类
 */
export class DeviceInfoUtil {
  /**
   * 获取鸿蒙PC基本信息
   * @returns 鸿蒙PC设备信息对象
   */
  static getDeviceBasicInfo(): Record<string, string> {
    return {
      deviceName: deviceInfo.deviceName,    // 鸿蒙PC设备名称
      deviceModel: deviceInfo.deviceModel,  // 鸿蒙PC设备型号
      osVersion: deviceInfo.osVersion,      // 鸿蒙PC系统版本
      manufacturer: deviceInfo.manufacturer  // 设备厂商(华为)
    };
  }

  /**
   * 获取鸿蒙PC唯一标识(需申请权限)
   * @returns 鸿蒙PC唯一标识
   */
  static getDeviceId(): string {
    return deviceInfo.deviceId;
  }
}
3.1.2 跨进程通信配置(Electron ↔ 鸿蒙 PC)
  • 鸿蒙 PC 端:在ElectronPage.ets中添加通信逻辑,通过WebViewonMessage监听 Electron 的请求,并返回鸿蒙 PC 设备信息:
import web_webview from '@ohos.web.webview';
import router from '@ohos.router';
import { DeviceInfoUtil } from '../utils/DeviceInfoUtil';

@Entry
@Component
struct ElectronPage {
  // WebView控制器
  private webViewController: web_webview.WebViewController = new web_webview.WebViewController();

  build() {
    Column({ space: 10 })
      .width('100%')
      .height('100%') {
        // WebView组件
        Web({
          src: $rawfile('index.html'),
          controller: this.webViewController
        })
        .width('100%')
        .height('90%')
        // 监听Electron发送的消息(适配鸿蒙PC通信)
        .onMessage((event) => {
          const message = event.message;
          // 处理“获取鸿蒙PC设备信息”请求
          if (message === 'getDeviceInfo') {
            const deviceInfo = DeviceInfoUtil.getDeviceBasicInfo();
            // 将鸿蒙PC设备信息发送给Electron
            this.webViewController.postMessage({
              type: 'deviceInfoResult',
              data: deviceInfo
            });
          }
        })

        Button('返回首页')
          .width(150)
          .height(40)
          .onClick(() => {
            router.back();
          })
      }
  }
}
  • Electron 端:修改index.html的脚本,发送请求并接收鸿蒙 PC 设备信息:
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>鸿蒙PC Electron Demo</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      text-align: center;
      padding-top: 50px;
    }
    #deviceInfo {
      margin-top: 30px;
      color: #333;
      font-size: 16px;
      line-height: 1.5;
    }
    button {
      padding: 10px 20px;
      font-size: 14px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <h1>Hello 鸿蒙PC Electron!</h1>
  <button id="getDeviceBtn">获取鸿蒙PC设备信息</button>
  <div id="deviceInfo"></div>

  <script>
    // 获取DOM元素
    const getDeviceBtn = document.getElementById('getDeviceBtn');
    const deviceInfoDiv = document.getElementById('deviceInfo');

    // 监听按钮点击:发送“获取鸿蒙PC设备信息”请求到鸿蒙端
    getDeviceBtn.addEventListener('click', () => {
      deviceInfoDiv.innerText = '正在获取鸿蒙PC设备信息...';
      // 通过WebView的postMessage发送请求(鸿蒙PC端监听该事件)
      if (window.webkit && window.webkit.messageHandlers) {
        // 鸿蒙PC WebView适配:通过webkit.messageHandlers发送消息
        window.webkit.messageHandlers.postMessage.postMessage('getDeviceInfo');
      }
    });

    // 监听鸿蒙PC端返回的消息
    window.addEventListener('message', (event) => {
      const { type, data } = event.data;
      if (type === 'deviceInfoResult') {
        // 渲染鸿蒙PC设备信息到页面
        deviceInfoDiv.innerText = `
          设备名称:${data.deviceName}
          设备型号:${data.deviceModel}
          系统版本:${data.osVersion}
          设备厂商:${data.manufacturer}
        `;
      }
    });
  </script>
</body>
</html>
3.1.3 调试步骤
  1. 将修改后的index.html复制到鸿蒙 PC 工程的rawfile目录;
  2. 启动鸿蒙 PC 设备(模拟器或真实设备),运行鸿蒙工程;
  3. 点击 “获取鸿蒙 PC 设备信息” 按钮,若页面显示鸿蒙 PC 的设备型号、系统版本等信息,则功能实现成功。

3.2 功能 2:Electron 与鸿蒙 PC 的文件交互(读写本地文件)

Electron 可通过 Node.js 的fs模块操作文件,鸿蒙 PC 端可通过fileIo模块读写文件,二者结合实现鸿蒙 PC 端的跨端文件共享。

3.2.1 Electron 端代码(文件写入鸿蒙 PC)

修改main.js,添加文件写入功能,并通过 IPC 通信接收渲染进程的文件内容(适配鸿蒙 PC 文件路径规范):

const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const fs = require('fs');  // 引入Node.js文件模块

let mainWindow;

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      nodeIntegration: true,
      contextIsolation: false
    }
  });

  mainWindow.loadFile('index.html');
  mainWindow.webContents.openDevTools();

  mainWindow.on('closed', () => {
    mainWindow = null;
  });
}

// 监听渲染进程的“写入文件到鸿蒙PC”请求
ipcMain.on('writeFile', (event, { filePath, content }) => {
  try {
    // 写入文件(鸿蒙PC端标准路径示例:/home/user/Documents/)
    const fullPath = path.join('/home/user/Documents/', filePath);
    fs.writeFileSync(fullPath, content, 'utf8');
    // 发送成功消息给渲染进程
    event.reply('writeFileResult', { success: true, message: `文件已保存至鸿蒙PC:${fullPath}` });
  } catch (error) {
    // 发送失败消息
    event.reply('writeFileResult', { success: false, message: error.message });
  }
});

app.whenReady().then(createWindow);
app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit();
});
3.2.2 Electron 渲染端代码(文件输入界面,适配鸿蒙 PC)

修改index.html,添加文件内容输入框和保存按钮(适配鸿蒙 PC 操作场景):

<!-- 新增文件操作区域(适配鸿蒙PC文件管理场景) -->
<div style="margin-top: 40px; padding: 0 20px;">
  <h3>文件写入测试(保存到鸿蒙PC)</h3>
  <input type="text" id="fileNameInput" placeholder="输入文件名(如test.txt)" style="width: 300px; padding: 8px; margin-right: 10px;">
  <textarea id="fileContentInput" placeholder="输入文件内容..." style="width: 100%; height: 150px; margin-top: 10px; padding: 8px;"></textarea>
  <button id="saveFileBtn" style="margin-top: 10px;">保存文件到鸿蒙PC</button>
  <div id="fileResult" style="margin-top: 10px; color: #666;"></div>
</div>

<script>
  // 新增:文件保存逻辑(适配鸿蒙PC)
  const fileNameInput = document.getElementById('fileNameInput');
  const fileContentInput = document.getElementById('fileContentInput');
  const saveFileBtn = document.getElementById('saveFileBtn');
  const fileResultDiv = document.getElementById('fileResult');

  // 监听保存按钮点击
  saveFileBtn.addEventListener('click', () => {
    const fileName = fileNameInput.value.trim();
    const content = fileContentInput.value.trim();

    if (!fileName) {
      fileResultDiv.innerText = '请输入文件名!';
      return;
    }

    // 通过ipcRenderer发送文件写入请求到主进程(目标:鸿蒙PC)
    window.ipcRenderer.send('writeFile', {
      filePath: fileName,
      content: content
    });
  });

  // 监听主进程返回的文件写入结果
  window.ipcRenderer.on('writeFileResult', (event, result) => {
    if (result.success) {
      fileResultDiv.innerText = `成功:${result.message}`;
      fileResultDiv.style.color = 'green';
    } else {
      fileResultDiv.innerText = `失败:${result.message}`;
      fileResultDiv.style.color = 'red';
    }
  });
</script>
3.2.3 鸿蒙 PC 端代码(文件读取)

DeviceInfoUtil.ets中添加鸿蒙 PC 文件读取方法:

import fileIo from '@ohos.file.fs';
import { BusinessError } from '@ohos.base';

export class DeviceInfoUtil {
  // ... 原有设备信息方法 ...

  /**
   * 读取鸿蒙PC本地文件
   * @param filePath 文件路径(如:/home/user/Documents/test.txt)
   * @returns 文件内容
   */
  static async readFile(filePath: string): Promise<string> {
    try {
      // 打开鸿蒙PC本地文件
      const file = await fileIo.open(filePath, fileIo.OpenMode.READ_ONLY);
      // 读取文件内容
      const buffer = new ArrayBuffer(4096);
      const readResult = await fileIo.read(file.fd, buffer);
      // 关闭文件
      await fileIo.close(file.fd);
      // 转换buffer为字符串
      return String.fromCharCode.apply(null, new Uint8Array(buffer.slice(0, readResult.bytesRead)));
    } catch (error) {
      const err = error as BusinessError;
      throw new Error(`鸿蒙PC文件读取失败:${err.message}`);
    }
  }
}

ElectronPage.ets中添加文件读取的通信逻辑(适配鸿蒙 PC):

// 新增:监听Electron的文件读取请求(鸿蒙PC端)
.webView.onMessage((event) => {
  const message = event.message;
  if (message === 'getDeviceInfo') {
    // ... 原有设备信息逻辑 ...
  } else if (message.type === 'readFile') {
    // 处理文件读取请求(鸿蒙PC本地文件)
    DeviceInfoUtil.readFile(message.filePath)
      .then(content => {
        this.webViewController.postMessage({
          type: 'readFileResult',
          success: true,
          content: content
        });
      })
      .catch(error => {
        this.webViewController.postMessage({
          type: 'readFileResult',
          success: false,
          message: error.message
        });
      });
  }
})
3.2.4 测试文件交互功能
  1. 在 Electron 界面输入文件名(如test.txt)和内容(如Hello HarmonyOS PC Electron!);
  2. 点击 “保存文件到鸿蒙 PC”,若提示 “文件已保存至鸿蒙 PC:/home/user/Documents/test.txt”,则写入成功;
  3. 在鸿蒙 PC 端调用readFile方法(可添加按钮触发),若能读取到文件内容,则鸿蒙 PC 与 Electron 的文件交互功能实现成功。

3.3 功能 3:分布式设备资源调用(以鸿蒙 PC 为核心)

借助鸿蒙的分布式软总线,鸿蒙 PC 上的 Electron 应用可调用其他鸿蒙设备的资源(如智慧屏的摄像头、手机的麦克风)。本节以 “鸿蒙 PC 调用智慧屏摄像头拍照” 为例,演示分布式功能。

3.3.1 鸿蒙 PC 端代码(分布式能力配置)
  1. 配置分布式权限:在module.json5中添加分布式相关权限(鸿蒙 PC 端必需):
{
  "module": {
    "abilities": [
      {
        // ... 原有配置 ...
        "permissions": [
          "ohos.permission.DISTRIBUTED_DATASYNC",  // 分布式数据同步权限(鸿蒙PC必需)
          "ohos.permission.CAMERA",                // 摄像头权限
          "ohos.permission.MICROPHONE"             // 麦克风权限(可选)
        ]
      }
    ]
  }
}
  1. 封装分布式摄像头工具类(适配鸿蒙 PC 作为核心调用端):在src/main/ets/utils目录下创建DistributedCameraUtil.ets
import distributedDevice from '@ohos.distributedDevice';
import camera from '@ohos.multimedia.camera';
import image from '@ohos.multimedia.image';
import { BusinessError } from '@ohos.base';

/**
 * 分布式摄像头工具类(鸿蒙PC为核心调用端)
 */
export class DistributedCameraUtil {
  private static cameraManager: camera.CameraManager | null = null;
  private static currentDeviceId: string = '';  // 分布式设备ID

  /**
   * 发现周边鸿蒙设备(鸿蒙PC主动发现)
   * @returns 设备列表(设备ID + 设备名称)
   */
  static async discoverDevices(): Promise<Array<{ deviceId: string; deviceName: string }>> {
    try {
      // 鸿蒙PC获取分布式设备列表
      const deviceList = await distributedDevice.getTrustedDeviceListSync();
      return deviceList.map(device => ({
        deviceId: device.deviceId,
        deviceName: device.deviceName
      }));
    } catch (error) {
      const err = error as BusinessError;
      throw new Error(`鸿蒙PC设备发现失败:${err.message}`);
    }
  }

  /**
   * 鸿蒙PC连接分布式设备的摄像头
   * @param deviceId 目标设备ID(如智慧屏)
   */
  static async connectCamera(deviceId: string): Promise<void> {
    try {
      // 保存目标设备ID
      this.currentDeviceId = deviceId;
      // 鸿蒙PC获取摄像头管理器(指定分布式设备ID)
      this.cameraManager = await camera.getCameraManager(deviceId);
      if (!this.cameraManager) {
        throw new Error('鸿蒙PC获取摄像头管理器失败');
      }
    } catch (error) {
      const err = error as BusinessError;
      throw new Error(`鸿蒙PC摄像头连接失败:${err.message}`);
    }
  }

  /**
   * 拍照(鸿蒙PC触发,目标设备执行,返回结果)
   * @returns 图片Base64字符串
   */
  static async takePhoto(): Promise<string> {
    if (!this.cameraManager || !this.currentDeviceId) {
      throw new Error('鸿蒙PC未连接分布式摄像头');
    }

    try {
      // 1. 鸿蒙PC获取目标设备摄像头列表
      const cameraList = await this.cameraManager.getCameraList();
      if (cameraList.length === 0) {
        throw new Error('目标设备无可用摄像头');
      }
      const cameraDevice = cameraList[0];  // 选择第一个摄像头

      // 2. 创建拍照会话
      const photoSession = await this.cameraManager.createPhotoSession({
        cameraDevice: cameraDevice,
        // 配置图片输出格式(JPEG)
        outputConfigs: [{
          format: image.ImageFormat.JPEG,
          size: { width: 1280, height: 720 }
        }]
      });

      // 3. 鸿蒙PC触发拍照
      const photoResult = await photoSession.takePhoto();
      // 4. 关闭会话
      await photoSession.close();

      // 5. 将图片转换为Base64(返回给鸿蒙PC的Electron应用)
      const imageBuffer = await photoResult.image.getBuffer();
      const base64Str = Buffer.from(imageBuffer).toString('base64');
      return base64Str;
    } catch (error) {
      const err = error as BusinessError;
      throw new Error(`拍照失败:${err.message}`);
    }
  }
}
3.3.2 Electron 端代码(分布式功能界面,鸿蒙 PC 为操作端)

index.html中添加分布式设备选择和拍照功能(适配鸿蒙 PC 操作场景)

<!-- 新增分布式摄像头区域(鸿蒙PC为核心调用端) -->
<div style="margin-top: 40px; padding: 0 20px; border-top: 1px solid #eee; padding-top: 20px;">
  <h3>分布式摄像头调用(鸿蒙PC为核心)</h3>
  <button id="discoverDevicesBtn">鸿蒙PC发现周边鸿蒙设备</button>
  <select id="deviceSelect" style="margin-left: 10px; padding: 8px; display: none;"></select>
  <button id="connectCameraBtn" style="margin-left: 10px; display: none;">连接目标设备摄像头</button>
  <button id="takePhotoBtn" style="margin-left: 10px; display: none;">拍照(鸿蒙PC触发)</button>
  <div id="cameraResult" style="margin-top: 20px;"></div>
  <img id="photoImg" style="margin-top: 10px; max-width: 100%; display: none;" alt="拍照结果">
</div>

<script>
  // 新增:分布式摄像头逻辑(鸿蒙PC为核心)
  const discoverDevicesBtn = document.getElementById('discoverDevicesBtn');
  const deviceSelect = document.getElementById('deviceSelect');
  const connectCameraBtn = document.getElementById('connectCameraBtn');
  const takePhotoBtn = document.getElementById('takePhotoBtn');
  const cameraResultDiv = document.getElementById('cameraResult');
  const photoImg = document.getElementById('photoImg');

  // 1. 鸿蒙PC发现周边设备
  discoverDevicesBtn.addEventListener('click', () => {
    cameraResultDiv.innerText = '鸿蒙PC正在发现周边鸿蒙设备...';
    // 发送设备发现请求到鸿蒙PC端
    window.webkit.messageHandlers.postMessage.postMessage({
      type: 'discoverDevices'
    });
  });

  // 2. 鸿蒙PC连接摄像头
  connectCameraBtn.addEventListener('click', () => {
    const selectedDeviceId = deviceSelect.value;
    if (!selectedDeviceId) {
      cameraResultDiv.innerText = '请选择目标设备!';
      return;
    }

    cameraResultDiv.innerText = '鸿蒙PC正在连接目标设备摄像头...';
    // 发送连接请求到鸿蒙PC端
    window.webkit.messageHandlers.postMessage.postMessage({
      type: 'connectCamera',
      deviceId: selectedDeviceId
    });
  });

  // 3. 鸿蒙PC触发拍照
  takePhotoBtn.addEventListener('click', () => {
    cameraResultDiv.innerText = '鸿蒙PC正在触发拍照...';
    // 发送拍照请求到鸿蒙PC端
    window.webkit.messageHandlers.postMessage.postMessage({
      type: 'takePhoto'
    });
  });

  // 监听鸿蒙PC端返回的分布式消息
  window.addEventListener('message', (event) => {
    const { type, data, success, message, base64Str } = event.data;

    switch (type) {
      case 'discoverDevicesResult':
        if (success) {
          // 渲染设备列表(鸿蒙PC发现的设备)
          deviceSelect.innerHTML = '';
          data.forEach(device => {
            const option = document.createElement('option');
            option.value = device.deviceId;
            option.text = device.deviceName;
            deviceSelect.appendChild(option);
          });
          deviceSelect.style.display = 'inline-block';
          connectCameraBtn.style.display = 'inline-block';
          cameraResultDiv.innerText = `鸿蒙PC发现${data.length}台鸿蒙设备`;
        } else {
          cameraResultDiv.innerText = `设备发现失败:${message}`;
        }
        break;

      case 'connectCameraResult':
        if (success) {
          takePhotoBtn.style.display = 'inline-block';
          cameraResultDiv.innerText = '摄像头连接成功,鸿蒙PC可点击拍照';
        } else {
          cameraResultDiv.innerText = `连接失败:${message}`;
        }
        break;

      case 'takePhotoResult':
        if (success) {
          // 显示拍照结果(Base64转图片,在鸿蒙PC上展示)
          photoImg.src = `data:image/jpeg;base64,${base64Str}`;
          photoImg.style.display = 'block';
          cameraResultDiv.innerText = '拍照成功(鸿蒙PC触发)';
        } else {
          cameraResultDiv.innerText = `拍照失败:${message}`;
        }
        break;
    }
  });
</script>
3.3.3 鸿蒙 PC 端代码(分布式通信逻辑)

ElectronPage.ets中添加分布式功能的通信处理(鸿蒙 PC 作为核心端):

import { DistributedCameraUtil } from '../utils/DistributedCameraUtil';

// 修改onMessage监听逻辑(鸿蒙PC端)
.webView.onMessage((event) => {
  const message = event.message;
  switch (message.type) {
    case 'getDeviceInfo':
      // ... 原有设备信息逻辑 ...
      break;

    case 'readFile':
      // ... 原有文件读取逻辑 ...
      break;

    case 'discoverDevices':
      // 处理鸿蒙PC的设备发现请求
      DistributedCameraUtil.discoverDevices()
        .then(devices => {
          this.webViewController.postMessage({
            type: 'discoverDevicesResult',
            success: true,
            data: devices
          });
        })
        .catch(error => {
          this.webViewController.postMessage({
            type: 'discoverDevicesResult',
            success: false,
            message: error.message
          });
        });
      break;

    case 'connectCamera':
      // 处理鸿蒙PC的摄像头连接请求
      DistributedCameraUtil.connectCamera(message.deviceId)
        .then(() => {
          this.webViewController.postMessage({
            type: 'connectCameraResult',
            success: true
          });
        })
        .catch(error => {
          this.webViewController.postMessage({
            type: 'connectCameraResult',
            success: false,
            message: error.message
          });
        });
      break;

    case 'takePhoto':
      // 处理鸿蒙PC的拍照请求
      DistributedCameraUtil.takePhoto()
        .then(base64Str => {
          this.webViewController.postMessage({
            type: 'takePhotoResult',
            success: true,
            base64Str: base64Str
          });
        })
        .catch(error => {
          this.webViewController.postMessage({
            type: 'takePhotoResult',
            success: false,
            message: error.message
          });
        });
      break;
  }
})
3.3.4 测试分布式功能
  1. 确保鸿蒙 PC 与智慧屏(或其他鸿蒙设备)处于同一局域网,并已登录同一华为账号(信任设备);
  2. 运行鸿蒙工程,点击 “鸿蒙 PC 发现周边鸿蒙设备”,若能显示智慧屏设备,则发现功能成功;
  3. 选择智慧屏,点击 “连接目标设备摄像头”,若提示 “摄像头连接成功,鸿蒙 PC 可点击拍照”,则连接功能成功;
  4. 点击 “拍照(鸿蒙 PC 触发)”,若能在鸿蒙 PC 的 Electron 界面显示智慧屏摄像头拍摄的图片,则分布式摄像头功能实现成功。

3.4 核心功能开发常见问题解决(鸿蒙 PC 场景)

问题现象 解决方案 参考链接
鸿蒙 PC 分布式设备发现为空 1. 确认鸿蒙 PC 与目标设备已登录同一华为账号;2. 开启鸿蒙 PC “分布式网络” 功能;3. 检查module.json5中已添加 DISTRIBUTED_DATASYNC 权限 鸿蒙分布式设备管理
摄像头调用报错 “Permission denied” 1. 在鸿蒙 PC 的 “设置> 应用 > 权限管理” 中授予应用摄像头权限;2. 确保module.json5中已添加 CAMERA 权限 鸿蒙应用权限申请
图片 Base64 显示空白(鸿蒙 PC 端) 1. 检查 Base64 字符串是否完整;2. 确认图片格式(JPEG/PNG)与data:image/xxx匹配;3. 缩小图片尺寸(避免鸿蒙 PC 端加载压力) 鸿蒙图片处理指南

四、鸿蒙 PC Electron 应用场景与进阶实践

4.1 典型应用场景(聚焦鸿蒙 PC)

4.1.1 企业办公软件
  • 场景描述:开发跨端办公套件(如文档编辑、会议软件),鸿蒙 PC 端用 Electron 实现复杂编辑功能,智慧屏端实现投屏演示,手机端实现移动审批。
  • 技术优势:复用 Web 技术栈的办公组件(如 Quill、TinyMCE),借助鸿蒙分布式能力实现 “鸿蒙 PC 编辑 - 智慧屏演示 - 手机审批” 无缝流转。
  • 案例参考:华为鸿蒙 PC 端的 “华为文档”,支持与手机、智慧屏同步编辑。
4.1.2 工具类应用
  • 场景描述:开发代码编辑器、思维导图工具,鸿蒙 PC 端用 Electron 实现高效编辑,平板端用鸿蒙实现手写批注,手机端实现文件管理。
  • 技术优势:Electron 支持 Node.js 后端能力(如代码编译、文件解析),鸿蒙 PC 支持键盘、鼠标精准操作,适配桌面端工具使用习惯。
  • 开发建议:使用 Monaco Editor(VS Code 核心)作为代码编辑组件,集成鸿蒙 PC 的快捷键适配 API 提升操作效率。
4.1.3 多媒体应用
  • 场景描述:开发视频剪辑、直播工具,鸿蒙 PC 端用 Electron 实现视频编辑,智慧屏端实现预览,手机端实现远程控制。
  • 技术优势:Electron 可集成 FFmpeg(视频处理)、WebRTC(直播),鸿蒙 PC 可调用本地高性能硬件资源,同时协同其他设备的音视频能力。
  • 资源推荐:Electron-FFmpeg 集成文档、鸿蒙 PC WebRTC 开发指南。

4.2 进阶实践:鸿蒙 PC 应用打包与发布

4.2.1 Electron 端打包(鸿蒙 PC 可执行文件)

使用electron-packager将 Electron 应用打包为鸿蒙 PC 端可执行文件:

  1. 安装打包工具:
npm install electron-packager --save-dev
  1. 添加打包脚本(package.json):
"scripts": {
  "start": "electron .",
  "package:harmonypc": "electron-packager . HarmonyElectronApp --platform linux --arch x64 --out dist --overwrite"
}
  1. 执行打包命令:
npm run package:harmonypc

打包结果位于dist/HarmonyElectronApp-linux-x64目录,可直接在鸿蒙 PC 端运行。

4.2.2 鸿蒙 PC 端打包(HAP 文件)

通过 DevEco Studio 打包鸿蒙应用为 HAP 文件(可发布到鸿蒙应用市场,供鸿蒙 PC 用户下载):

  1. 配置签名:进入「Project Structure > Project > Signing Configs」,创建签名证书(需申请鸿蒙开发者账号);
  2. 打包 HAP:点击「Build > Build HAP (s)」,生成的 HAP 文件位于build/outputs/hap目录;
  3. 发布渠道:通过鸿蒙应用市场开发者平台提交 HAP 文件审核,审核通过后即可供鸿蒙 PC 用户下载安装。

4.3 性能优化建议(针对鸿蒙 PC)

  • 减少 Electron 窗口渲染压力:
    1. 使用webPreferences.plugins = false禁用不必要插件,降低鸿蒙 PC 资源占用;
    2. 适配鸿蒙 PC 屏幕分辨率,避免过度缩放导致的渲染卡顿。
  • 优化鸿蒙 PC 分布式通信:
    1. 鸿蒙 PC 作为核心端,减少跨设备数据传输量(如压缩图片、分块传输);
    2. 使用鸿蒙的DistributedData模块在鸿蒙 PC 本地缓存常用数据,避免重复请求。
  • 内存管理:
    1. Electron 主进程避免创建过多窗口(鸿蒙 PC 端每个窗口占用独立内存);
    2. 鸿蒙 PC 端及时释放不再使用的资源(如关闭摄像头会话、释放文件句柄)。

五、总结与资源推荐

5.1 开发总结

鸿蒙 PC 与 Electron 结合,为桌面端全场景应用开发提供了 “Web 技术复用 + 分布式能力” 的新路径,尤其适配鸿蒙 PC 的生态建设需求。核心要点总结如下:

  • 环境搭建:需同步配置 Node.js(16.x)、Electron(22.3.2)、DevEco Studio(4.0+),确保与鸿蒙 PC 版本兼容;
  • 核心通信:通过 WebView 的onMessagepostMessage实现 Electron 与鸿蒙 PC 的跨进程通信;
  • 分布式能力:以鸿蒙 PC 为核心,借助鸿蒙的distributedDevicecamera等模块,实现多设备资源调用;
  • 场景落地:适合企业办公、工具类、多媒体等鸿蒙 PC 高频使用场景,可快速复用 Web 生态资源,加速鸿蒙 PC 应用开发。

5.2 官方资源推荐

  • 鸿蒙 PC 开发官网:HarmonyOS for PC 开发者文档
  • Electron 官方指南:Electron 快速入门
  • 鸿蒙分布式能力:HarmonyOS 分布式技术文档
  • 鸿蒙 API 参考:HarmonyOS API 9 文档

5.3 学习路径建议

  • 入门阶段:掌握 Electron 基础(窗口创建、IPC 通信)、鸿蒙 PC DevEco Studio 使用;
  • 进阶阶段:学习鸿蒙 PC 分布式 API、Electron 与鸿蒙 PC 的通信适配;
  • 实战阶段:开发小型工具应用(如记事本、图片查看器),熟悉鸿蒙 PC 应用打包与发布流程;
  • 深入阶段:优化鸿蒙 PC 应用性能、集成复杂功能(如视频处理、数据库),参与开源项目。

欢迎加入开源鸿蒙 PC 社区,与更多开发者交流技术、共享资源、共建生态:https://harmonypc.csdn.net/

通过本文的代码示例与指南,希望能帮助开发者快速上手鸿蒙 PC Electron 开发,共同推动鸿蒙 PC 桌面端生态的完善与发展。若在实践中遇到问题,可通过鸿蒙开发者论坛(HarmonyOS 开发者论坛)、Electron 社区(Electron Community)或开源鸿蒙 PC 社区寻求帮助。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐