鸿蒙 Electron 进阶实战:从多窗口管理到系统级交互(鸿蒙PC)
随着鸿蒙生态对桌面应用场景的覆盖,鸿蒙 Electron 已从 “基础适配” 走向 “深度融合”。本文聚焦进阶开发场景,通过多窗口协同、系统通知集成、文件关联等实战案例,结合鸿蒙特有能力(如原子化服务调用),帮你打造更贴近系统体验的跨端应用。全文配套可复用源码与官方调试工具链接,解决进阶开发中的高频问题。
一、鸿蒙 Electron 进阶开发核心场景
相比基础开发,进阶场景更注重 “应用与系统的融合” 和 “复杂交互的实现”,需重点掌握三类核心能力。
1.1 进阶开发的核心方向
- 多窗口协同:实现主窗口、弹窗、子窗口的通信与状态同步(如 “设置窗口修改配置后,主窗口实时更新”)。
- 系统级交互:调用鸿蒙系统能力,如系统通知、文件关联、快捷键注册,让应用更贴近原生体验。
- 鸿蒙能力深度集成:结合原子化服务、分布式任务调度,突破传统 Electron 的功能边界。
官方进阶文档参考:鸿蒙 Electron 系统能力调用指南
1.2 进阶开发的前置准备
- 环境升级:确保 DevEco Studio 版本≥5.0 Release,鸿蒙 SDK 升级至 API Version 11(支持更多系统能力)。
- 工具补充:安装鸿蒙系统能力调试工具
harmony-tools,用于测试系统 API 调用:
运行
# 全局安装调试工具
npm install -g @harmonyos/electron-tools
# 验证安装
harmony-tools -v
# 输出“1.1.0”即成功
- 权限配置:在
harmony.json中提前添加进阶场景所需权限(如系统通知、文件读写):
"permissions": [
"ohos.permission.POST_NOTIFICATIONS", // 系统通知权限
"ohos.permission.READ_USER_STORAGE", // 读取存储权限
"ohos.permission.WRITE_USER_STORAGE", // 写入存储权限
"ohos.permission.REGISTER_APP_SCHEME" // 应用Scheme注册权限
]
二、实战 1:多窗口协同与状态同步
多窗口是桌面应用的常见形态,鸿蒙 Electron 中需解决 “窗口通信”“状态共享”“窗口生命周期管理” 三个核心问题。
2.1 场景需求
开发一个 “文档编辑器” 应用,包含:
- 主窗口(文档编辑)
- 设置窗口(修改字体、主题)
- 预览窗口(实时预览文档效果)要求:设置窗口修改配置后,主窗口与预览窗口同步更新;预览窗口关闭时不影响主窗口运行。
2.2 核心实现代码
2.2.1 主进程:窗口创建与通信管理(main/index.js)
运行
const { app, BrowserWindow, ipcMain, dialog } = require('@harmonyos/electron');
const path = require('path');
// 存储窗口实例(便于管理)
let mainWindow, settingWindow, previewWindow;
// 共享状态(配置信息)
let appConfig = {
fontSize: 16,
theme: 'light',
previewEnabled: true
};
// 创建主窗口
function createMainWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
preload: path.join(__dirname, 'preload.js') // 预加载脚本(共享状态)
},
harmonyOptions: {
supportedDevices: ['pc', 'tablet']
}
});
mainWindow.loadFile('renderer/main.html');
// 主窗口菜单:添加“打开设置”“打开预览”选项
mainWindow.webContents.on('did-finish-load', () => {
mainWindow.webContents.send('config-update', appConfig); // 初始发送配置
});
// 监听“打开设置窗口”请求
ipcMain.handle('open-setting-window', () => {
if (settingWindow) {
settingWindow.show(); // 已存在则显示,避免重复创建
return;
}
settingWindow = new BrowserWindow({
width: 600,
height: 400,
parent: mainWindow, // 设置父窗口(主窗口关闭时,子窗口也关闭)
modal: false, // 非模态(可同时操作主窗口)
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
settingWindow.loadFile('renderer/setting.html');
// 设置窗口关闭时清空实例
settingWindow.on('closed', () => {
settingWindow = null;
});
});
// 监听“打开预览窗口”请求
ipcMain.handle('open-preview-window', (event, content) => {
if (!appConfig.previewEnabled) {
dialog.showErrorBox('预览未启用', '请在设置中开启预览功能');
return;
}
if (previewWindow) {
previewWindow.webContents.send('preview-update', content);
previewWindow.show();
return;
}
previewWindow = new BrowserWindow({
width: 800,
height: 600,
parent: mainWindow,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
previewWindow.loadFile('renderer/preview.html');
// 初始发送文档内容
previewWindow.webContents.on('did-finish-load', () => {
previewWindow.webContents.send('preview-update', content);
previewWindow.webContents.send('config-update', appConfig);
});
// 预览窗口关闭时清空实例
previewWindow.on('closed', () => {
previewWindow = null;
});
});
// 监听“配置修改”请求(来自设置窗口)
ipcMain.handle('update-config', (event, newConfig) => {
appConfig = { ...appConfig, ...newConfig };
// 同步更新主窗口与预览窗口的配置
if (mainWindow) mainWindow.webContents.send('config-update', appConfig);
if (previewWindow) previewWindow.webContents.send('config-update', appConfig);
return { success: true };
});
}
app.whenReady().then(createMainWindow);
// 关闭所有窗口时退出应用
app.on('window-all-closed', () => {
mainWindow = null;
settingWindow = null;
previewWindow = null;
if (process.platform !== 'darwin') app.quit();
});

2.2.2 预加载脚本:共享状态与安全通信(main/preload.js)
// 预加载脚本:向渲染进程暴露安全的API(避免直接暴露nodeIntegration)
const { contextBridge, ipcRenderer } = require('@harmonyos/electron');
contextBridge.exposeInMainWorld('appApi', {
// 获取应用配置
getConfig: () => ipcRenderer.invoke('get-config'),
// 打开设置窗口
openSettingWindow: () => ipcRenderer.invoke('open-setting-window'),
// 打开预览窗口
openPreviewWindow: (content) => ipcRenderer.invoke('open-preview-window', content),
// 监听配置更新
onConfigUpdate: (callback) => ipcRenderer.on('config-update', (event, config) => callback(config))
});
2.2.3 主窗口渲染逻辑(renderer/js/main.js)
运行
// 主窗口:文档编辑与窗口控制
const { ipcRenderer } = require('@harmonyos/electron');
const editor = document.getElementById('editor');
const openSettingBtn = document.getElementById('openSettingBtn');
const openPreviewBtn = document.getElementById('openPreviewBtn');
// 监听配置更新(来自主进程)
ipcRenderer.on('config-update', (event, config) => {
// 应用字体大小与主题
editor.style.fontSize = `${config.fontSize}px`;
document.body.className = config.theme;
});
// 打开设置窗口
openSettingBtn.addEventListener('click', () => {
ipcRenderer.invoke('open-setting-window');
});
// 打开预览窗口(传递当前文档内容)
openPreviewBtn.addEventListener('click', () => {
ipcRenderer.invoke('open-preview-window', editor.value);
});
// 文档内容变化时,实时更新预览窗口(如果已打开)
editor.addEventListener('input', () => {
if (previewWindow) {
ipcRenderer.send('update-preview-content', editor.value);
}
});
2.2.4 设置窗口渲染逻辑(renderer/js/setting.js)
运行
// 设置窗口:修改配置并同步
const { ipcRenderer } = require('@harmonyos/electron');
const fontSizeSelect = document.getElementById('fontSizeSelect');
const themeSelect = document.getElementById('themeSelect');
const previewSwitch = document.getElementById('previewSwitch');
const saveBtn = document.getElementById('saveBtn');
// 初始加载当前配置
ipcRenderer.on('config-update', (event, config) => {
fontSizeSelect.value = config.fontSize;
themeSelect.value = config.theme;
previewSwitch.checked = config.previewEnabled;
});
// 保存配置并通知主进程
saveBtn.addEventListener('click', async () => {
const newConfig = {
fontSize: parseInt(fontSizeSelect.value),
theme: themeSelect.value,
previewEnabled: previewSwitch.checked
};
const result = await ipcRenderer.invoke('update-config', newConfig);
if (result.success) {
alert('配置保存成功');
// 关闭设置窗口(可选)
window.close();
}
});
2.3 关键技术点总结
- 窗口父子关系:通过
parent属性绑定子窗口(如设置窗口)到主窗口,主窗口关闭时子窗口自动关闭,避免内存泄漏。 - 状态共享:主进程维护全局
appConfig,配置修改后通过webContents.send同步到所有窗口。 - 窗口复用:判断窗口实例是否存在,避免重复创建(如
if (settingWindow) settingWindow.show())。

三、实战 2:系统级交互能力集成
让应用 “融入” 鸿蒙系统,需调用系统级 API,本节以 “系统通知”“文件关联”“全局快捷键” 三个高频场景为例。
3.1 场景 1:系统通知(任务完成时推送提醒)
3.1.1 主进程代码(main/notification.js)
const { Notification } = require('@harmonyos/electron');
const path = require('path');
// 发送系统通知
function sendSystemNotification(title, body) {
// 检查通知权限(鸿蒙系统需手动授权)
if (Notification.isSupported()) {
const notification = new Notification({
title: title,
body: body,
icon: path.join(__dirname, '../resources/icon.png'), // 通知图标
harmonyOptions: {
notificationType: 'reminder', // 通知类型(提醒型)
importance: 1 // 重要性(1-3,3最高)
}
});
// 监听通知点击事件(点击后激活主窗口)
notification.on('click', () => {
if (mainWindow) {
mainWindow.show();
mainWindow.focus();
}
});
notification.show();
}
}
// 示例:文档保存成功后发送通知
ipcMain.handle('save-document', async (event, content, path) => {
// 模拟保存逻辑
await fs.promises.writeFile(path, content);
// 发送通知
sendSystemNotification('文档保存成功', `文件已保存至:${path}`);
return { success: true };
});
3.1.2 权限申请说明
鸿蒙系统中,POST_NOTIFICATIONS权限需用户手动授权,可在应用启动时触发授权弹窗:
// 主进程:应用就绪后请求通知权限
app.whenReady().then(async () => {
const { notificationPermission } = require('@harmonyos/electron/system');
const permission = await notificationPermission.request();
console.log('通知权限状态:', permission); // granted/denied
});
3.2 场景 2:文件关联(双击鸿蒙系统中的.txt 文件,用当前应用打开)
3.2.1 配置文件关联(package.json)
"harmonyElectron": {
"build": {
"fileAssociations": [
{
"ext": ["txt", "md"], // 关联的文件后缀
"name": "Text File", // 文件类型名称
"description": "Text and Markdown files",
"icon": "resources/file-icons/{ext}.png" // 文件图标(按后缀区分)
}
]
}
}
3.2.2 主进程处理文件打开事件
// 主进程:监听文件打开事件(双击文件时触发)
app.on('open-file', (event, filePath) => {
event.preventDefault(); // 阻止系统默认行为
// 1. 如果应用未启动,先创建主窗口
if (!mainWindow) {
createMainWindow();
// 窗口创建完成后读取文件
mainWindow.on('ready-to-show', async () => {
const content = await fs.promises.readFile(filePath, 'utf8');
mainWindow.webContents.send('open-file', { path: filePath, content: content });
});
} else {
// 2. 应用已启动,直接发送文件内容到主窗口
fs.promises.readFile(filePath, 'utf8').then(content => {
mainWindow.webContents.send('open-file', { path: filePath, content: content });
mainWindow.show();
});
}
});
3.2.3 渲染进程接收文件内容
运行
// 渲染进程:接收并加载打开的文件
ipcRenderer.on('open-file', (event, { path, content }) => {
document.getElementById('editor').value = content;
document.title = `文档编辑器 - ${path}`; // 更新窗口标题为文件名
});
3.3 场景 3:全局快捷键(注册 “Ctrl+S” 保存、“Ctrl+P” 预览)
3.3.1 主进程注册全局快捷键
const { globalShortcut } = require('@harmonyos/electron');
// 应用就绪后注册快捷键
app.whenReady().then(() => {
// 注册“Ctrl+S”保存快捷键
const saveShortcut = globalShortcut.register('Ctrl+S', () => {
if (mainWindow) {
// 向主窗口发送保存指令
mainWindow.webContents.send('trigger-save');
}
});
// 注册“Ctrl+P”预览快捷键
const previewShortcut = globalShortcut.register('Ctrl+P', () => {
if (mainWindow) {
// 先获取当前文档内容,再打开预览窗口
mainWindow.webContents.executeJavaScript(`document.getElementById('editor').value`).then(content => {
ipcRenderer.invoke('open-preview-window', content);
});
}
});
// 检查快捷键是否注册成功
if (!saveShortcut) console.error('“Ctrl+S”快捷键注册失败(可能已被占用)');
if (!previewShortcut) console.error('“Ctrl+P”快捷键注册失败(可能已被占用)');
});
// 应用退出时注销所有快捷键(避免残留)
app.on('will-quit', () => {
globalShortcut.unregisterAll();
});
3.3.2 渲染进程响应快捷键指令
运行
// 渲染进程:监听“触发保存”指令
ipcRenderer.on('trigger-save', () => {
// 执行保存逻辑(如调用保存接口)
document.getElementById('saveBtn').click();
});

四、实战 3:鸿蒙原子化服务调用(进阶融合)
原子化服务是鸿蒙的核心特性之一,鸿蒙 Electron 可通过harmony:service API 调用系统或第三方原子化服务(如 “文件压缩”“OCR 识别”)。
4.1 场景需求
在文档编辑器中添加 “OCR 识别” 功能:用户上传图片,调用鸿蒙系统的 OCR 原子化服务,将图片中的文字提取到编辑器中。
4.2 核心实现代码
4.2.1 主进程调用原子化服务(main/ocr-service.js)
const { ipcMain, dialog } = require('@harmonyos/electron');
const { service } = require('@harmonyos/electron/harmony');
// 调用OCR原子化服务
async function callOcrService(imagePath) {
try {
// 1. 检查OCR服务是否可用
const isAvailable = await service.checkAvailability('ohos.service.ocr');
if (!isAvailable) {
throw new Error('OCR原子化服务未安装,请在鸿蒙应用市场搜索“OCR识别”并安装');
}
// 2. 调用OCR服务(传递图片路径)
const result = await service.invoke('ohos.service.ocr', 'recognizeText', {
imagePath: imagePath,
language: 'zh-CN' // 识别语言
});
// 3. 返回识别结果
return result.text;
} catch (error) {
console.error('OCR服务调用失败:', error);
throw error;
}
}
// 监听“OCR识别”请求(来自渲染进程)
ipcMain.handle('ocr-recognize', async () => {
// 1. 打开文件选择器,让用户选择图片
const { filePaths } = await dialog.showOpenDialog({
title: '选择图片文件',
filters: [
{ name: 'Image Files', extensions: ['png', 'jpg', 'jpeg'] }
],
properties: ['openFile']
});
if (!filePaths || filePaths.length === 0) {
throw new Error('未选择图片文件');
}
const imagePath = filePaths[0];
// 2. 调用OCR服务
const recognizedText = await callOcrService(imagePath);
// 3. 返回识别结果到渲染进程
return { success: true, text: recognizedText };
});
4.2.2 渲染进程触发 OCR 识别(renderer/js/ocr.js)
运行
const { ipcRenderer } = require('@harmonyos/electron');
const ocrBtn = document.getElementById('ocrBtn');
const editor = document.getElementById('editor');
ocrBtn.addEventListener('click', async () => {
try {
const result = await ipcRenderer.invoke('ocr-recognize');
if (result.success) {
// 将识别结果插入到编辑器光标位置
const start = editor.selectionStart;
const end = editor.selectionEnd;
const currentContent = editor.value;
editor.value = currentContent.substring(0, start) + result.text + currentContent.substring(end);
alert('OCR识别成功,已插入文本');
}
} catch (error) {
alert('OCR识别失败:' + error.message);
}
});
4.3 关键说明
- 原子化服务依赖:调用第三方原子化服务前,需确保用户设备已安装该服务(可通过
service.checkAvailability检查)。 - 服务参数格式:不同原子化服务的调用参数不同,需参考服务提供方的文档(如 OCR 服务的
imagePath参数需为绝对路径)。 - 权限要求:调用原子化服务可能需要额外权限(如 “访问其他应用”),需在
harmony.json中添加对应权限。
五、进阶开发避坑指南
进阶开发中,易遇到 “权限不足”“窗口内存泄漏”“服务调用失败” 等问题,以下为高频坑点及解决方案。
5.1 坑点 1:系统 API 调用提示 “权限不足”
- 现象:调用系统通知、文件关联等 API 时,报错 “permission denied”。
- 原因:
harmony.json中未配置对应权限。- 部分权限(如通知、存储)需用户手动授权,未触发授权流程。
- 解决方案:
- 检查
harmony.json的permissions字段,确保包含所需权限(参考本文 1.2 节)。 - 调用权限相关 API 时,先通过
@harmonyos/electron/system模块请求授权:
运行
const { notificationPermission, storagePermission } = require('@harmonyos/electron/system'); // 请求通知权限 const notifyPerm = await notificationPermission.request(); // 请求存储权限 const storagePerm = await storagePermission.request(); - 检查
5.2 坑点 2:窗口关闭后内存泄漏
- 现象:多次打开并关闭子窗口后,应用内存占用持续升高。
- 原因:未清空窗口实例,或窗口关闭时未注销事件监听。
- 解决方案:
- 窗口关闭时,将实例设为
null(参考本文 2.2.1 节settingWindow.on('closed'))。 - 注销窗口相关的事件监听(如
ipcMain.removeListener):
运行
settingWindow.on('closed', () => { ipcMain.removeListener('update-config', updateConfigHandler); // 注销事件 settingWindow = null; }); - 窗口关闭时,将实例设为
5.3 坑点 3:原子化服务调用失败
- 现象:调用
service.invoke时,报错 “service not found” 或 “invalid parameters”。 - 原因:
- 服务未安装或服务 ID 错误。
- 传递的参数格式不符合服务要求。
- 解决方案:
- 通过
service.checkAvailability(服务ID)确认服务是否可用,若不可用则提示用户安装。 - 查阅服务官方文档,确认参数格式(如图片路径需为绝对路径,且文件存在)。
- 通过
六、鸿蒙 Electron 进阶资源汇总
6.1 官方进阶工具与文档
- 鸿蒙 Electron 系统能力调试工具:https://developer.harmonyos.com/cn/develop/deveco-studio/tool/harmony-tools-0000001578624551
- 原子化服务调用手册:https://developer.harmonyos.com/cn/docs/design/electron/service-invocation-0000001578624549
- 鸿蒙系统权限列表:https://developer.harmonyos.com/cn/docs/design/electron/permission-list-0000001578624545
6.2 第三方进阶案例库
- 鸿蒙 Electron 多窗口示例:https://github.com/harmonyos/electron-samples/tree/main/multi-window
- 系统交互功能示例:https://github.com/harmonyos/electron-samples/tree/main/system-interaction
七、总结与未来方向
鸿蒙 Electron 的进阶开发,核心是 “从‘能用’到‘好用’” 的跨越 —— 通过多窗口协同提升复杂场景体验,通过系统级交互贴近原生感受,通过原子化服务扩展功能边界。本文的实战案例可直接复用于文档编辑、代码编辑器、办公软件等桌面应用场景。
未来,鸿蒙 Electron 将进一步深化与鸿蒙生态的融合,例如支持鸿蒙的 “多端 UI 自适应”(一套 UI 自动适配 PC、平板、手机)、“分布式文件系统”(跨设备访问文件)等能力。建议开发者持续关注官方更新,将新能力快速应用到实际项目中。
如果在进阶开发中遇到特定场景的问题,可通过鸿蒙开发者论坛的 “Electron 进阶” 板块提问,或参考本文提供的示例代码与工具链接排查问题。
欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/
更多推荐
所有评论(0)