鸿蒙系统与 Electron 结合开发:从环境搭建到核心功能落地(附完整代码)
本文介绍了Electron与鸿蒙系统(HarmonyOS)结合的跨端开发方案。Electron基于Web技术栈可快速开发桌面应用,而鸿蒙系统具备分布式能力,二者结合可实现"一次编写、多端运行"的全场景应用体验。文章详细讲解了开发环境搭建、核心功能实现(包括设备信息获取、文件交互和分布式设备调用)以及应用打包发布流程。通过实际代码示例,展示了如何利用鸿蒙的分布式特性扩展Elect
前言
在跨端开发领域,Electron 凭借 “一次编写、多端运行” 的特性占据重要地位,其基于 Chromium 和 Node.js 的架构可快速将 Web 应用打包为 Windows、macOS、Linux 桌面应用。而鸿蒙系统(HarmonyOS)作为面向全场景的分布式操作系统,正逐步完善桌面端(如鸿蒙 PC、智慧屏)生态。将 Electron 与鸿蒙结合,既能复用 Web 技术栈的海量资源,又能借助鸿蒙的分布式能力实现 “跨设备无缝流转”,为开发者提供更灵活的全场景应用开发方案。
本文面向有 Web 或桌面开发基础的开发者,从技术背景、环境搭建、核心功能开发到场景落地,全程附代码示例与官方文档链接,助力快速上手鸿蒙 Electron 开发。
一、鸿蒙与 Electron 结合的技术背景
1.1 为什么需要鸿蒙 + Electron?
- 技术复用:Electron 基于 Web 技术栈(HTML/CSS/JavaScript),开发者无需学习全新语言即可开发鸿蒙桌面应用,降低迁移成本。
- 跨端能力互补:Electron 擅长桌面端应用开发,鸿蒙擅长分布式跨设备协同,二者结合可实现 “桌面端功能 + 多设备流转” 的全场景体验(如 PC 端编辑文档,智慧屏端展示)。
- 生态适配需求:鸿蒙桌面端(如华为 MateBook X Pro 2024 款鸿蒙版)需要更多优质应用,Electron 可将现有桌面应用快速适配鸿蒙,加速生态建设。
1.2 核心技术原理
鸿蒙系统通过方舟引擎(Ark Engine)支持 Electron 应用运行,其核心逻辑是:
- Electron 应用的 Chromium 内核与鸿蒙的图形渲染框架适配,确保界面正常显示;
- Electron 的 Node.js 层与鸿蒙的系统 API 桥接,实现文件操作、设备调用等原生能力;
- 借助鸿蒙的分布式软总线,Electron 应用可调用其他鸿蒙设备的资源(如摄像头、扬声器)。
1.3 官方资源参考
- 鸿蒙桌面端开发官网:HarmonyOS for PC 开发指南
- Electron 官方文档:Electron 官方指南
- 鸿蒙与 Electron 适配说明:HarmonyOS 第三方框架适配文档
二、鸿蒙 Electron 开发环境搭建(附代码与操作步骤)
环境搭建分为 3 个核心步骤:基础环境(Node.js+Electron)、鸿蒙开发环境(DevEco Studio)、工程初始化与依赖配置。全程基于 Windows 11 系统演示,macOS/Linux 步骤类似。
2.1 基础环境准备(Node.js + Electron)
2.1.1 安装 Node.js
Electron 依赖 Node.js 环境,需安装Node.js 16.x LTS 版本(经测试与鸿蒙适配最佳,高版本可能存在兼容性问题)。
- 下载地址:Node.js 16.20.2 官网下载
- 安装后验证:打开命令行(CMD 或 PowerShell),执行以下命令,输出版本号即安装成功:
bash
node -v # 需输出 v16.20.2
npm -v # 需输出 8.19.4(Node.js 16.x 默认版本)
2.1.2 安装 Electron
通过 npm 全局安装 Electron,指定版本为22.3.2(与鸿蒙方舟引擎适配的稳定版本):
bash
# 全局安装Electron
npm install -g electron@22.3.2
# 验证安装
electron -v # 需输出 v22.3.2
2.2 鸿蒙开发环境配置(DevEco Studio)
鸿蒙应用的编译、打包与设备调试需通过 DevEco Studio 完成,需安装DevEco Studio 4.0 及以上版本。
-
下载地址:DevEco Studio 官网下载
-
安装步骤:
- 双击安装包,选择 “自定义安装”,勾选 “HarmonyOS SDK for PC”(桌面端开发必需);
- 安装完成后,打开 DevEco Studio,自动下载鸿蒙 PC 端 SDK(版本选择 3.2.100 及以上);
- 配置 SDK 路径:进入「File > Settings > Appearance & Behavior > System Settings > HarmonyOS SDK」,确认 “PC” 选项卡下的 SDK 已全部下载。
-
验证环境:
- 打开 DevEco Studio,创建一个 “Empty Ability” 项目,模板选择 “PC”;
- 连接鸿蒙 PC 设备或启动鸿蒙 PC 模拟器(需在「Tools > Device Manager」中申请);
- 点击 “Run” 按钮,若项目能正常运行(显示默认页面),则鸿蒙环境配置成功。
2.3 鸿蒙 Electron 工程初始化(附代码)
2.3.1 创建 Electron 基础工程
- 新建文件夹(如
HarmonyElectronDemo),打开命令行进入该文件夹,执行以下命令初始化 Electron 工程:
bash
# 初始化package.json(一路回车默认配置即可)
npm init -y
# 安装本地Electron依赖(确保与全局版本一致)
npm install electron@22.3.2 --save-dev
- 在工程根目录创建 3 个核心文件:
main.js:Electron 主进程文件(控制应用生命周期、创建窗口);index.html:应用界面文件(Web 端页面);preload.js:主进程与渲染进程的通信桥接文件。
2.3.2 核心文件代码实现
(1)main.js(Electron 主进程)
javascript
// 引入Electron核心模块
const { app, BrowserWindow } = require('electron');
const path = require('path');
// 避免垃圾回收导致窗口被销毁
let mainWindow;
// 创建窗口函数
function createWindow() {
mainWindow = new BrowserWindow({
width: 800, // 窗口宽度
height: 600, // 窗口高度
webPreferences: {
// 配置预加载脚本(用于主进程与渲染进程通信)
preload: path.join(__dirname, 'preload.js'),
// 启用Node.js环境(鸿蒙端需开启)
nodeIntegration: true,
contextIsolation: false // 关闭上下文隔离(适配鸿蒙API调用)
}
});
// 加载本地HTML文件
mainWindow.loadFile('index.html');
// 打开开发者工具(调试用,发布时需注释)
mainWindow.webContents.openDevTools();
// 窗口关闭事件
mainWindow.on('closed', () => {
mainWindow = null;
});
}
// 应用就绪后创建窗口
app.whenReady().then(() => {
createWindow();
// 适配macOS(窗口关闭后重新打开)
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// 所有窗口关闭后退出应用(Windows/Linux)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
(2)preload.js(通信桥接)
javascript
// 暴露Electron的ipcRenderer到渲染进程(用于跨进程通信)
window.ipcRenderer = require('electron').ipcRenderer;
(3)index.html(应用界面)
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>鸿蒙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;
}
</style>
</head>
<body>
<h1>Hello 鸿蒙Electron!</h1>
<button id="getDeviceBtn">获取鸿蒙设备信息</button>
<div id="deviceInfo"></div>
<script>
// 监听按钮点击事件
document.getElementById('getDeviceBtn').addEventListener('click', () => {
// 后续章节将通过鸿蒙API获取设备信息,此处先占位
document.getElementById('deviceInfo').innerText = '待获取设备信息...';
});
</script>
</body>
</html>
2.3.3 配置工程运行脚本
修改package.json,添加scripts字段,用于启动 Electron 应用:
json
{
"name": "harmony-electron-demo",
"version": "1.0.0",
"main": "main.js", // 指定主进程文件
"scripts": {
"start": "electron ." // 启动命令
},
"devDependencies": {
"electron": "^22.3.2"
}
}
2.3.4 测试 Electron 工程
在命令行执行以下命令,若能弹出窗口并显示 “Hello 鸿蒙 Electron!”,则基础工程搭建成功:
bash
npm run start
2.4 鸿蒙端工程配置(对接 Electron)
- 打开 DevEco Studio,创建一个 “Empty Ability” 项目,项目名称为
HarmonyElectronHost,模板选择 “PC”,包名自定义(如com.example.harmonyelectronhost)。 - 在鸿蒙工程的
main_pages.json中添加 Electron 应用的启动页面配置:
json
{
"src": [
"main_pages/Index",
{
"src": "electron/ElectronPage",
"window": {
"designWidth": 800,
"autoDesignWidth": true
}
}
]
}
- 在
src/main/electron目录下创建ElectronPage.ets文件,用于加载 Electron 应用:
typescript
import web_webview from '@ohos.web.webview';
import router from '@ohos.router';
@Entry
@Component
struct ElectronPage {
build() {
Column({ space: 10 }) {
// 鸿蒙WebView组件:加载Electron应用的本地HTML
Web({
src: $rawfile('index.html'), // 需将Electron工程的index.html放入鸿蒙工程的rawfile目录
controller: new web_webview.WebViewController()
})
.width('100%')
.height('90%')
// 返回按钮
Button('返回首页')
.width(150)
.height(40)
.onClick(() => {
router.back();
})
}
.width('100%')
.height('100%')
}
}
-
资源复制:将 Electron 工程中的
index.html、preload.js复制到鸿蒙工程的src/main/rawfile目录(若没有rawfile目录,需手动创建)。 -
测试鸿蒙对接:
- 启动鸿蒙 PC 模拟器或连接真实设备;
- 点击 DevEco Studio 的 “Run” 按钮,进入
ElectronPage页面,若能显示 Electron 应用的界面,则鸿蒙端配置成功。
2.5 环境搭建常见问题解决
| 问题现象 | 解决方案 | 参考链接 |
|---|---|---|
| Electron 启动报错 “Cannot find module 'electron'” | 1. 检查 Node.js 版本是否为 16.x;2. 执行npm install重新安装依赖;3. 全局安装 Electron:npm install -g electron@22.3.2 |
Electron 安装问题排查 |
| 鸿蒙 WebView 加载 HTML 报错 “File not found” | 1. 确认 HTML 文件路径是否正确;2. 检查rawfile目录是否在src/main下;3. 清理工程缓存:「Build > Clean Project」 |
鸿蒙 WebView 资源加载指南 |
| DevEco Studio 无法识别鸿蒙 PC 设备 | 1. 安装鸿蒙设备驱动:鸿蒙设备驱动下载;2. 开启设备 “开发者模式” 并允许 USB 调试 | 鸿蒙设备连接指南 |
三、鸿蒙 Electron 核心功能开发(多代码示例)
本节聚焦 3 个核心功能:鸿蒙设备信息获取、Electron 与鸿蒙的跨进程通信、分布式设备资源调用,每个功能均附完整代码与调试步骤。
3.1 功能 1:鸿蒙设备信息获取(Electron 调用鸿蒙 API)
通过鸿蒙的deviceInfo模块获取设备型号、系统版本等信息,并在 Electron 界面展示。
3.1.1 鸿蒙端代码(能力封装)
在鸿蒙工程的src/main/ets/utils目录下创建DeviceInfoUtil.ets,封装设备信息获取方法:
typescript
import deviceInfo from '@ohos.device.deviceInfo';
/**
* 鸿蒙设备信息工具类
*/
export class DeviceInfoUtil {
/**
* 获取设备基本信息
* @returns 设备信息对象
*/
static getDeviceBasicInfo(): Record<string, string> {
return {
deviceName: deviceInfo.deviceName, // 设备名称
deviceModel: deviceInfo.deviceModel, // 设备型号
osVersion: deviceInfo.osVersion, // 系统版本
manufacturer: deviceInfo.manufacturer // 设备厂商
};
}
/**
* 获取设备唯一标识(需申请权限)
* @returns 设备唯一标识
*/
static getDeviceId(): string {
return deviceInfo.deviceId;
}
}
3.1.2 跨进程通信配置(Electron ↔ 鸿蒙)
- 鸿蒙端:在
ElectronPage.ets中添加通信逻辑,通过WebView的onMessage监听 Electron 的请求,并返回设备信息:
typescript
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发送的消息
.onMessage((event) => {
const message = event.message;
// 处理“获取设备信息”请求
if (message === 'getDeviceInfo') {
const deviceInfo = DeviceInfoUtil.getDeviceBasicInfo();
// 将设备信息发送给Electron
this.webViewController.postMessage({
type: 'deviceInfoResult',
data: deviceInfo
});
}
})
Button('返回首页')
.width(150)
.height(40)
.onClick(() => {
router.back();
})
}
}
}
- Electron 端:修改
index.html的脚本,发送请求并接收设备信息:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>鸿蒙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 鸿蒙Electron!</h1>
<button id="getDeviceBtn">获取鸿蒙设备信息</button>
<div id="deviceInfo"></div>
<script>
// 获取DOM元素
const getDeviceBtn = document.getElementById('getDeviceBtn');
const deviceInfoDiv = document.getElementById('deviceInfo');
// 监听按钮点击:发送“获取设备信息”请求到鸿蒙端
getDeviceBtn.addEventListener('click', () => {
deviceInfoDiv.innerText = '正在获取设备信息...';
// 通过WebView的postMessage发送请求(鸿蒙端监听该事件)
if (window.webkit && window.webkit.messageHandlers) {
// 鸿蒙WebView适配:通过webkit.messageHandlers发送消息
window.webkit.messageHandlers.postMessage.postMessage('getDeviceInfo');
}
});
// 监听鸿蒙端返回的消息
window.addEventListener('message', (event) => {
const { type, data } = event.data;
if (type === 'deviceInfoResult') {
// 渲染设备信息到页面
deviceInfoDiv.innerText = `
设备名称:${data.deviceName}
设备型号:${data.deviceModel}
系统版本:${data.osVersion}
设备厂商:${data.manufacturer}
`;
}
});
</script>
</body>
</html>
3.1.3 调试步骤
- 将修改后的
index.html复制到鸿蒙工程的rawfile目录; - 启动鸿蒙设备,运行鸿蒙工程;
- 点击 “获取鸿蒙设备信息” 按钮,若页面显示设备型号、系统版本等信息,则功能实现成功。
3.2 功能 2:Electron 与鸿蒙的文件交互(读写本地文件)
Electron 可通过 Node.js 的fs模块操作文件,鸿蒙端可通过fileIo模块读写文件,二者结合实现跨端文件共享。
3.2.1 Electron 端代码(文件写入)
修改main.js,添加文件写入功能,并通过 IPC 通信接收渲染进程的文件内容:
javascript
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;
});
}
// 监听渲染进程的“写入文件”请求
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: `文件已保存至:${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 渲染端代码(文件输入界面)
修改index.html,添加文件内容输入框和保存按钮:
html
<!-- 新增文件操作区域 -->
<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>
// 新增:文件保存逻辑
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发送文件写入请求到主进程
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 鸿蒙端代码(文件读取)
在DeviceInfoUtil.ets中添加文件读取方法:
typescript
import fileIo from '@ohos.file.fs';
import { BusinessError } from '@ohos.base';
export class DeviceInfoUtil {
// ... 原有设备信息方法 ...
/**
* 读取鸿蒙本地文件
* @param filePath 文件路径(如:/home/user/Documents/test.txt)
* @returns 文件内容
*/
static async readFile(filePath: string): Promise<string> {
try {
// 打开文件
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(`文件读取失败:${err.message}`);
}
}
}
在ElectronPage.ets中添加文件读取的通信逻辑:
typescript
// 新增:监听Electron的文件读取请求
.webView.onMessage((event) => {
const message = event.message;
if (message.type === 'getDeviceInfo') {
// ... 原有设备信息逻辑 ...
} else if (message.type === 'readFile') {
// 处理文件读取请求
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 测试文件交互功能
- 在 Electron 界面输入文件名(如
test.txt)和内容(如Hello HarmonyOS Electron!); - 点击 “保存文件到鸿蒙 PC”,若提示 “文件已保存至:/home/user/Documents/test.txt”,则写入成功;
- 在鸿蒙端调用
readFile方法(可添加按钮触发),若能读取到文件内容,则文件交互功能实现成功。
3.3 功能 3:分布式设备资源调用(鸿蒙特色)
借助鸿蒙的分布式软总线,Electron 应用可调用其他鸿蒙设备的资源(如智慧屏的摄像头、手机的麦克风)。本节以 “调用智慧屏摄像头拍照” 为例,演示分布式功能。
3.3.1 鸿蒙端代码(分布式能力配置)
- 配置分布式权限:在
module.json5中添加分布式相关权限:
json
{
"module": {
"abilities": [
{
// ... 原有配置 ...
"permissions": [
"ohos.permission.DISTRIBUTED_DATASYNC", // 分布式数据同步权限
"ohos.permission.CAMERA", // 摄像头权限
"ohos.permission.MICROPHONE" // 麦克风权限(可选)
]
}
]
}
}
- 封装分布式摄像头工具类:在
src/main/ets/utils目录下创建DistributedCameraUtil.ets:
typescript
import distributedDevice from '@ohos.distributedDevice';
import camera from '@ohos.multimedia.camera';
import image from '@ohos.multimedia.image';
import { BusinessError } from '@ohos.base';
/**
* 分布式摄像头工具类
*/
export class DistributedCameraUtil {
private static cameraManager: camera.CameraManager | null = null;
private static currentDeviceId: string = ''; // 分布式设备ID
/**
* 发现周边鸿蒙设备
* @returns 设备列表(设备ID + 设备名称)
*/
static async discoverDevices(): Promise<Array<{ deviceId: string; deviceName: string }>> {
try {
// 获取分布式设备列表
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(`设备发现失败:${err.message}`);
}
}
/**
* 连接分布式设备的摄像头
* @param deviceId 目标设备ID
*/
static async connectCamera(deviceId: string): Promise<void> {
try {
// 保存目标设备ID
this.currentDeviceId = deviceId;
// 获取摄像头管理器(指定分布式设备ID)
this.cameraManager = await camera.getCameraManager(deviceId);
if (!this.cameraManager) {
throw new Error('获取摄像头管理器失败');
}
} catch (error) {
const err = error as BusinessError;
throw new Error(`摄像头连接失败:${err.message}`);
}
}
/**
* 拍照(返回图片Base64)
* @returns 图片Base64字符串
*/
static async takePhoto(): Promise<string> {
if (!this.cameraManager || !this.currentDeviceId) {
throw new Error('未连接分布式摄像头');
}
try {
// 1. 获取摄像头列表
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. 开始拍照
const photoResult = await photoSession.takePhoto();
// 4. 关闭会话
await photoSession.close();
// 5. 将图片转换为Base64
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 端代码(分布式功能界面)
在index.html中添加分布式设备选择和拍照功能:
html
<!-- 新增分布式摄像头区域 -->
<div style="margin-top: 40px; padding: 0 20px; border-top: 1px solid #eee; padding-top: 20px;">
<h3>分布式摄像头调用(鸿蒙特色)</h3>
<button id="discoverDevicesBtn">发现周边鸿蒙设备</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;">拍照</button>
<div id="cameraResult" style="margin-top: 20px;"></div>
<img id="photoImg" style="margin-top: 10px; max-width: 100%; display: none;" alt="拍照结果">
</div>
<script>
// 新增:分布式摄像头逻辑
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. 发现周边设备
discoverDevicesBtn.addEventListener('click', () => {
cameraResultDiv.innerText = '正在发现周边鸿蒙设备...';
// 发送设备发现请求到鸿蒙端
window.webkit.messageHandlers.postMessage.postMessage({
type: 'discoverDevices'
});
});
// 2. 连接摄像头
connectCameraBtn.addEventListener('click', () => {
const selectedDeviceId = deviceSelect.value;
if (!selectedDeviceId) {
cameraResultDiv.innerText = '请选择目标设备!';
return;
}
cameraResultDiv.innerText = '正在连接目标设备摄像头...';
// 发送连接请求到鸿蒙端
window.webkit.messageHandlers.postMessage.postMessage({
type: 'connectCamera',
deviceId: selectedDeviceId
});
});
// 3. 拍照
takePhotoBtn.addEventListener('click', () => {
cameraResultDiv.innerText = '正在拍照...';
// 发送拍照请求到鸿蒙端
window.webkit.messageHandlers.postMessage.postMessage({
type: 'takePhoto'
});
});
// 监听鸿蒙端返回的分布式消息
window.addEventListener('message', (event) => {
const { type, data, success, message, base64Str } = event.data;
switch (type) {
case 'discoverDevicesResult':
if (success) {
// 渲染设备列表
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 = `发现${data.length}台鸿蒙设备`;
} else {
cameraResultDiv.innerText = `设备发现失败:${message}`;
}
break;
case 'connectCameraResult':
if (success) {
takePhotoBtn.style.display = 'inline-block';
cameraResultDiv.innerText = '摄像头连接成功,可点击拍照';
} else {
cameraResultDiv.innerText = `连接失败:${message}`;
}
break;
case 'takePhotoResult':
if (success) {
// 显示拍照结果(Base64转图片)
photoImg.src = `data:image/jpeg;base64,${base64Str}`;
photoImg.style.display = 'block';
cameraResultDiv.innerText = '拍照成功';
} else {
cameraResultDiv.innerText = `拍照失败:${message}`;
}
break;
}
});
</script>
3.3.3 鸿蒙端代码(分布式通信逻辑)
在ElectronPage.ets中添加分布式功能的通信处理:
typescript
import { DistributedCameraUtil } from '../utils/DistributedCameraUtil';
// 修改onMessage监听逻辑
.webView.onMessage((event) => {
const message = event.message;
switch (message.type) {
case 'getDeviceInfo':
// ... 原有设备信息逻辑 ...
break;
case 'readFile':
// ... 原有文件读取逻辑 ...
break;
case 'discoverDevices':
// 处理设备发现请求
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':
// 处理摄像头连接请求
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':
// 处理拍照请求
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 测试分布式功能
- 确保鸿蒙 PC 与智慧屏(或其他鸿蒙设备)处于同一局域网,并已登录同一华为账号(信任设备);
- 运行鸿蒙工程,点击 “发现周边鸿蒙设备”,若能显示智慧屏设备,则发现功能成功;
- 选择智慧屏,点击 “连接摄像头”,若提示 “摄像头连接成功”,则连接功能成功;
- 点击 “拍照”,若能显示智慧屏摄像头拍摄的图片,则分布式摄像头功能实现成功。
3.4 核心功能开发常见问题解决
| 问题现象 | 解决方案 | 参考链接 |
|---|---|---|
| 分布式设备发现为空 | 1. 确认设备已登录同一华为账号;2. 开启设备 “分布式网络” 功能;3. 检查权限是否添加(DISTRIBUTED_DATASYNC) | 鸿蒙分布式设备管理 |
| 摄像头调用报错 “Permission denied” | 1. 在鸿蒙设备的 “设置> 应用 > 权限管理” 中授予应用摄像头权限;2. 确保module.json5中已添加 CAMERA 权限 |
鸿蒙应用权限申请 |
| 图片 Base64 显示空白 | 1. 检查 Base64 字符串是否完整;2. 确认图片格式(JPEG/PNG)与data:image/xxx匹配;3. 缩小图片尺寸(避免 Base64 过长) |
鸿蒙图片处理指南 |
四、鸿蒙 Electron 应用场景与进阶实践
4.1 典型应用场景
4.1.1 企业办公软件
- 场景描述:开发跨端办公套件(如文档编辑、会议软件),PC 端用 Electron 实现复杂编辑功能,智慧屏端实现投屏演示,手机端实现移动审批。
- 技术优势:复用 Web 技术栈的办公组件(如 Quill、TinyMCE),借助鸿蒙分布式能力实现 “编辑 - 演示 - 审批” 无缝流转。
- 案例参考:华为鸿蒙 PC 端的 “华为文档”,支持与手机、智慧屏同步编辑。
4.1.2 工具类应用
- 场景描述:开发代码编辑器、思维导图工具,PC 端用 Electron 实现高效编辑,平板端用鸿蒙实现手写批注,手机端实现文件管理。
- 技术优势:Electron 支持 Node.js 后端能力(如代码编译、文件解析),鸿蒙支持手写笔、触摸屏等硬件适配。
- 开发建议:使用 Monaco Editor(VS Code 核心)作为代码编辑组件,集成鸿蒙的手写笔 API 实现批注功能。
4.1.3 多媒体应用
- 场景描述:开发视频剪辑、直播工具,PC 端用 Electron 实现视频编辑,智慧屏端实现预览,手机端实现远程控制。
- 技术优势:Electron 可集成 FFmpeg(视频处理)、WebRTC(直播),鸿蒙可调用多设备的音视频资源(如 PC 麦克风、智慧屏扬声器)。
- 资源推荐:Electron-FFmpeg 集成文档、鸿蒙 WebRTC 开发指南。
4.2 进阶实践:应用打包与发布
4.2.1 Electron 端打包(鸿蒙 PC)
使用electron-packager将 Electron 应用打包为鸿蒙 PC 端可执行文件:
- 安装打包工具:
bash
npm install electron-packager --save-dev
- 添加打包脚本(
package.json):
json
"scripts": {
"start": "electron .",
"package:harmony": "electron-packager . HarmonyElectronApp --platform linux --arch x64 --out dist --overwrite"
}
- 执行打包命令:
bash
npm run package:harmony
- 打包结果位于
dist/HarmonyElectronApp-linux-x64目录,可直接在鸿蒙 PC 端运行。
4.2.2 鸿蒙端打包(HAP 文件)
通过 DevEco Studio 打包鸿蒙应用为 HAP 文件(可发布到鸿蒙应用市场):
- 配置签名:进入「Project Structure > Project > Signing Configs」,创建签名证书(需申请鸿蒙开发者账号);
- 打包 HAP:点击「Build > Build HAP (s)」,生成的 HAP 文件位于
build/outputs/hap目录; - 发布渠道:通过鸿蒙应用市场开发者平台提交 HAP 文件审核。
4.3 性能优化建议
-
减少 Electron 窗口渲染压力:
- 使用
webPreferences.plugins = false禁用插件; - 避免大量 DOM 操作,使用虚拟列表(如 Vue Virtual Scroller)处理长列表。
- 使用
-
优化鸿蒙分布式通信:
- 减少跨设备数据传输量(如压缩图片、分块传输);
- 使用鸿蒙的
DistributedData模块缓存常用数据,避免重复请求。
-
内存管理:
- Electron 主进程避免创建过多窗口(每个窗口占用独立内存);
- 鸿蒙端及时释放不再使用的资源(如关闭摄像头会话、释放文件句柄)。
五、总结与资源推荐
5.1 开发总结
鸿蒙与 Electron 结合,为全场景应用开发提供了 “Web 技术复用 + 分布式能力” 的新路径。核心要点总结如下:
- 环境搭建:需同步配置 Node.js(16.x)、Electron(22.3.2)、DevEco Studio(4.0+),确保版本兼容;
- 核心通信:通过 WebView 的
onMessage和postMessage实现 Electron 与鸿蒙的跨进程通信; - 分布式能力:借助鸿蒙的
distributedDevice、camera等模块,实现多设备资源调用; - 场景落地:适合企业办公、工具类、多媒体等场景,可快速复用 Web 生态资源。
5.2 官方资源推荐
- 鸿蒙桌面端开发:HarmonyOS for PC 开发者文档
- Electron 官方指南:Electron 快速入门
- 鸿蒙分布式能力:HarmonyOS 分布式技术文档
- 鸿蒙 API 参考:HarmonyOS API 9 文档
5.3 学习路径建议
- 入门阶段:掌握 Electron 基础(窗口创建、IPC 通信)、鸿蒙 DevEco Studio 使用;
- 进阶阶段:学习鸿蒙分布式 API、Electron 与鸿蒙的通信适配;
- 实战阶段:开发小型工具应用(如记事本、图片查看器),熟悉打包与发布流程;
- 深入阶段:优化性能、集成复杂功能(如视频处理、数据库),参与开源项目。
通过本文的代码示例与指南,希望能帮助开发者快速上手鸿蒙 Electron 开发,共同推动鸿蒙桌面端生态的完善。若在实践中遇到问题,可通过鸿蒙开发者论坛(HarmonyOS 开发者论坛)或 Electron 社区(Electron Community)寻求帮助。
更多推荐






所有评论(0)