鸿蒙 Electron 的 “原子化服务” 适配:轻量级应用打包与鸿蒙服务卡片集成指南
本文探讨了Electron应用适配鸿蒙原子化服务的完整流程。Electron凭借Web技术栈优势成为跨平台开发热门选择,而鸿蒙原子化服务具有免安装、轻量化等特点。文章从技术原理到实战案例,详细解析了适配方案:首先通过依赖裁剪和资源压缩实现Electron应用轻量化(控制在10MB内);然后将其封装为鸿蒙HAP包,配置免安装启动;接着开发服务卡片作为入口;最后建立双向通信机制。通过一个笔记工具案例,
引言:Electron 与鸿蒙原子化服务的碰撞
在跨平台应用开发领域,Electron 凭借 “HTML+CSS+JavaScript” 的技术栈优势,成为桌面应用开发的热门选择(如 VS Code、Slack 均基于 Electron 构建)。而华为鸿蒙(HarmonyOS)作为面向全场景的分布式操作系统,其核心特性 “原子化服务” 打破了传统应用的安装壁垒,实现了 “即用即走、免安装” 的轻量化体验。
当 Electron 应用遇上鸿蒙原子化服务,开发者可以同时兼顾跨平台开发效率与鸿蒙生态的全场景能力 —— 既保留 Electron 对 Web 技术栈的兼容性,又能借助鸿蒙服务卡片、分布式流转等特性,让应用渗透到手机、平板、智慧屏等多终端场景。
本文将从 技术原理、环境搭建、轻量级打包、服务卡片集成、通信机制、实战案例、问题排查 七个维度,全面解析 Electron 应用适配鸿蒙原子化服务的完整流程,附带可直接复用的代码片段和官方文档链接,助力开发者快速落地适配工作。
本文适用于:Electron 开发者、鸿蒙生态开发者、跨平台应用工程师,需具备基础的 Node.js 开发经验和鸿蒙应用开发入门知识。参考文档:
一、核心概念解析:原子化服务与 Electron 适配逻辑
在开始实操前,需先明确两个核心技术的适配逻辑,避免踩坑:
1.1 鸿蒙原子化服务核心特性
原子化服务是鸿蒙生态的核心组件,本质是 免安装、轻量化、可被直接调用的应用形态,其核心特性包括:
- 免安装启动:用户无需下载安装包,通过桌面卡片、搜索、分享等方式直接启动服务;
- 服务卡片:支持在鸿蒙桌面展示核心功能(如天气、待办、数据统计),点击卡片可跳转至完整应用;
- 分布式流转:服务可在多终端间无缝切换(如手机启动的 Electron 应用,流转至智慧屏继续使用);
- 轻量化打包:以 HAP(HarmonyOS Ability Package)为载体,单个原子化服务包体积通常小于 10MB。
1.2 Electron 应用适配鸿蒙的核心挑战
Electron 应用的传统打包产物(如 .exe、.dmg)体积较大(通常 50MB+),且依赖系统原生环境,无法直接适配鸿蒙原子化服务的 “轻量化、免安装” 要求。因此,适配的核心逻辑是:
- 对 Electron 应用进行 瘦身优化,降低打包体积;
- 将优化后的 Electron 应用封装为鸿蒙 HAP 包,使其支持原子化服务启动;
- 开发鸿蒙 服务卡片,实现核心功能的桌面展示与应用跳转;
- 打通 Electron 应用与鸿蒙系统的 通信通道(如数据交互、生命周期管理)。
二、前置准备:开发环境搭建
2.1 鸿蒙开发环境配置
步骤 1:安装 DevEco Studio
- 下载地址:DevEco Studio 官方下载
- 版本要求:DevEco Studio 4.0+(支持原子化服务打包)
- 配置鸿蒙 SDK:安装 API Version 9+(原子化服务最低支持 API 9),具体步骤参考 鸿蒙 SDK 安装指南
步骤 2:配置鸿蒙开发者账号与签名
- 注册鸿蒙开发者账号:华为开发者联盟
- 申请应用签名:原子化服务打包需使用官方签名,参考 鸿蒙应用签名配置指南
- 开通原子化服务权限:在华为开发者联盟后台,申请 “原子化服务发布” 权限(个人开发者需完成实名认证)
2.2 Electron 开发环境配置
步骤 1:安装 Node.js 与 Electron
- Node.js 版本要求:16.x+(推荐 18.x LTS),下载地址:Node.js 官方下载
- 初始化 Electron 项目:
bash
运行
# 创建项目目录 mkdir electron-harmony-atomic-service && cd electron-harmony-atomic-service # 初始化 npm 项目 npm init -y # 安装 Electron(指定 25.x 版本,兼容性更优) npm install electron@25.9.0 --save-dev
步骤 2:安装核心依赖工具
electron-builder:Electron 打包工具,支持自定义打包配置;electron-packager:轻量级打包工具,用于快速生成精简版应用;@ohos/hap-toolkit:鸿蒙 HAP 包打包工具;node-ipc:Electron 与鸿蒙系统的进程间通信工具。
安装命令:
bash
运行
npm install electron-builder electron-packager @ohos/hap-toolkit node-ipc --save-dev
2.3 环境验证
- 验证鸿蒙环境:启动 DevEco Studio,创建 “原子化服务” 项目(模板选择 “Empty Ability”),能正常编译运行则环境配置成功;
- 验证 Electron 环境:在项目根目录创建
main.js,写入以下代码:javascript
运行
创建const { app, BrowserWindow } = require('electron'); function createWindow() { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true } }); win.loadFile('index.html'); } app.whenReady().then(createWindow);index.html:html
预览
在<!DOCTYPE html> <html> <body> <h1>Electron 鸿蒙原子化服务适配Demo</h1> </body> </html>package.json中添加启动脚本:json
运行"scripts": { "start": "electron ." }npm start,能正常启动 Electron 窗口则环境配置成功。
三、Electron 应用轻量级打包:体积优化与适配改造
Electron 应用的默认打包体积较大,需通过 “依赖裁剪、资源压缩、打包配置优化” 实现轻量化,使其满足鸿蒙原子化服务的体积要求(建议压缩至 10MB 以内)。
3.1 依赖裁剪:移除冗余依赖
步骤 1:分析依赖体积
使用 webpack-bundle-analyzer 分析项目依赖,找出冗余依赖:
bash
运行
npm install webpack-bundle-analyzer --save-dev
在项目根目录创建 webpack.config.js:
javascript
运行
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [new BundleAnalyzerPlugin()]
};
运行 npx webpack --config webpack.config.js,浏览器会自动打开依赖分析页面,重点关注体积较大的非必要依赖。
步骤 2:替换重量级依赖
- 用
axios替换superagent(体积减少 50%+); - 用
dayjs替换moment.js(体积减少 80%+); - 移除开发环境依赖(如
eslint、mocha),确保仅保留生产环境依赖:bash
运行
# 卸载开发依赖 npm uninstall eslint mocha --save-dev # 安装轻量级替代依赖 npm install axios dayjs --save
3.2 资源压缩:优化静态资源
步骤 1:压缩 HTML/CSS/JS
- 使用
html-minifier-terser压缩 HTML:bash
运行
创建npm install html-minifier-terser --save-devcompress-html.js:javascript
运行
const htmlMinifier = require('html-minifier-terser'); const fs = require('fs'); const html = fs.readFileSync('index.html', 'utf8'); const minifiedHtml = htmlMinifier.minify(html, { removeComments: true, collapseWhitespace: true, minifyCSS: true, minifyJS: true }); fs.writeFileSync('dist/index.html', minifiedHtml); - 使用
csso压缩 CSS,terser压缩 JS,同理创建压缩脚本。
步骤 2:优化图片资源
- 将图片格式转换为 WebP(体积减少 60%+),使用 Squoosh 在线压缩;
- 移除图片中的 Exif 信息,使用
exiftool工具:bash
运行
# 安装 exiftool(需先安装 Perl) npm install exiftool --save-dev
3.3 Electron 打包配置优化
使用 electron-packager 进行轻量级打包,配置如下:
步骤 1:修改 package.json 打包脚本
json
"scripts": {
"start": "electron .",
"package:light": "electron-packager . electron-harmony --platform=linux --arch=x64 --out=dist --overwrite --asar --prune=true --ignore=node_modules/electron --ignore=node_modules/.bin --ignore=tests"
}
参数说明:
--asar:将应用资源打包为 asar 归档文件,减少文件数量;--prune=true:自动移除 node_modules 中的冗余文件;--ignore:忽略不需要打包的文件(如测试目录、Electron 源码);--platform=linux:鸿蒙系统基于 Linux 内核,需指定 Linux 平台。
步骤 2:运行打包命令
bash
运行
npm run package:light
打包完成后,在 dist/electron-harmony-linux-x64 目录下生成精简版 Electron 应用,体积可控制在 8-10MB(取决于应用复杂度)。
3.4 验证打包产物
运行打包后的应用,确保核心功能正常:
bash
运行
cd dist/electron-harmony-linux-x64
./electron-harmony
若能正常启动,说明轻量级打包成功。
进阶优化:使用
electron-builder配置extraResources仅包含必要资源,或通过electron-merge合并冗余模块,进一步压缩体积。参考 Electron 体积优化官方指南
四、鸿蒙原子化服务适配:HAP 包封装与配置
将轻量化后的 Electron 应用封装为鸿蒙 HAP 包,使其支持原子化服务的启动、安装与分发。
4.1 创建鸿蒙原子化服务项目
- 打开 DevEco Studio,点击 “File → New → Project”;
- 选择 “HarmonyOS → Atomic Service”,模板选择 “Empty Ability”;
- 配置项目信息:
- Project Name:
ElectronAtomicService; - Package Name:
com.example.electronatomicservice(需与开发者联盟后台一致); - API Version:9+;
- Ability Type:
Service Ability(原子化服务核心能力)。
- Project Name:
4.2 导入 Electron 打包产物
- 在鸿蒙项目的
main_pages目录下,创建electron文件夹; - 将 Electron 打包后的
electron-harmony-linux-x64目录下的所有文件,复制到electron文件夹中; - 在
electron目录下创建run.sh脚本,用于启动 Electron 应用:bash
运行
给脚本添加执行权限:#!/bin/sh cd $(dirname $0) ./electron-harmonybash
运行
chmod +x run.sh
4.3 配置 HAP 包清单文件(config.json)
config.json 是鸿蒙应用的核心配置文件,需配置原子化服务的基本信息、权限、启动入口等。修改 entry/src/main/config.json:
json
{
"app": {
"bundleName": "com.example.electronatomicservice",
"vendor": "example",
"version": {
"code": 1000000,
"name": "1.0.0"
},
"apiVersion": {
"compatible": 9,
"target": 9
}
},
"module": {
"package": "com.example.electronatomicservice",
"name": "entry",
"mainAbility": "com.example.electronatomicservice.MainAbility",
"deviceTypes": ["phone", "tablet", "tv"], // 支持的终端类型
"distro": {
"deliveryWithInstall": false, // 原子化服务:免安装
"moduleName": "entry",
"moduleType": "entry",
"installationFree": true // 启用免安装模式
},
"abilities": [
{
"name": "com.example.electronatomicservice.MainAbility",
"type": "service",
"visible": true,
"skills": [
{
"entities": ["entity.system.service"],
"actions": ["action.system.start"]
}
],
"backgroundModes": ["dataTransfer"],
"launchType": "singleton"
}
],
"resources": {
"rawFile": [
{
"path": "electron" // 导入的 Electron 资源
}
]
},
"permissions": [
{
"name": "ohos.permission.EXECUTE_SHELL_COMMAND" // 执行 Shell 脚本权限
}
]
}
}
关键配置说明:
deliveryWithInstall: false:原子化服务无需随系统安装;installationFree: true:启用免安装模式;permissions:申请执行 Shell 脚本的权限(启动 Electron 应用需此权限);rawFile:指定导入的 Electron 资源目录。
4.4 实现 Ability 启动逻辑
修改 entry/src/main/java/com/example/electronatomicservice/MainAbility.java,在 onStart 方法中启动 Electron 应用:
java
运行
package com.example.electronatomicservice;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import java.io.IOException;
public class MainAbility extends Ability {
private static final HiLogLabel LABEL = new HiLogLabel(HiLog.DEBUG, 0x00001, "ElectronAtomicService");
private Process electronProcess;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
HiLog.info(LABEL, "Electron atomic service started");
// 启动 Electron 应用
new Thread(() -> {
try {
Context context = getContext();
// 获取 Electron 资源路径
String electronPath = context.getBundleResourceManager().getRawFileEntry("electron/run.sh").getFile().getPath();
HiLog.info(LABEL, "Electron run path: " + electronPath);
// 执行启动脚本
ProcessBuilder pb = new ProcessBuilder(electronPath);
pb.redirectErrorStream(true);
electronProcess = pb.start();
// 等待进程结束
electronProcess.waitFor();
} catch (IOException | InterruptedException e) {
HiLog.error(LABEL, "Failed to start Electron app: " + e.getMessage());
}
}).start();
}
@Override
public void onStop() {
super.onStop();
// 停止 Electron 进程
if (electronProcess != null && isAlive(electronProcess)) {
electronProcess.destroy();
HiLog.info(LABEL, "Electron app stopped");
}
}
private boolean isAlive(Process process) {
try {
process.exitValue();
return false;
} catch (IllegalThreadStateException e) {
return true;
}
}
}
4.5 编译 HAP 包
- 在 DevEco Studio 中,点击 “Build → Build HAP (s)/APP (s) → Build HAP (s)”;
- 编译成功后,在
entry/build/outputs/hap/release目录下生成 HAP 包(entry-release.hap); - 验证 HAP 包:通过鸿蒙模拟器或真实设备安装 HAP 包,启动原子化服务,能正常打开 Electron 应用则适配成功。
注意:若出现 “权限不足” 错误,需在设备的 “设置 → 应用 → 权限管理” 中,给应用授予 “执行 Shell 命令” 权限;若启动失败,可通过
HiLog日志排查问题(DevEco Studio 的 “Logcat” 面板查看)。
五、鸿蒙服务卡片集成:桌面展示与应用跳转
鸿蒙服务卡片是原子化服务的核心入口,支持在桌面展示应用核心功能,点击卡片可直接启动 Electron 应用。本节将实现一个 “数据统计” 类型的服务卡片,展示 Electron 应用的核心数据,并支持跳转至应用。
5.1 创建服务卡片
- 在 DevEco Studio 中,右键点击
entry/src/main目录,选择 “New → Service Widget”; - 配置卡片信息:
- Widget Name:
ElectronWidget; - Widget Size:选择 “2x2”(桌面 2x2 网格大小);
- Template:选择 “Default”。
- Widget Name:
5.2 设计卡片布局(widget_layout.xml)
修改 entry/src/main/resources/base/layout/widget_layout.xml,设计卡片 UI(展示应用名称、数据统计、跳转按钮):
xml
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:width="match_parent"
ohos:height="match_parent"
ohos:orientation="vertical"
ohos:background_element="#f5f5f5">
<!-- 卡片标题 -->
<Text
ohos:width="match_parent"
ohos:height="40vp"
ohos:text="Electron 原子化服务"
ohos:text_size="18fp"
ohos:text_weight="bold"
ohos:gravity="center"
ohos:background_element="#2f54eb"/>
<!-- 数据统计展示 -->
<DirectionalLayout
ohos:width="match_parent"
ohos:height="80vp"
ohos:orientation="horizontal"
ohos:gravity="center"
ohos:top_margin="10vp">
<Text
ohos:width="wrap_content"
ohos:height="wrap_content"
ohos:text="今日访问:"
ohos:text_size="16fp"
ohos:text_color="#333"/>
<Text
ohos:id="$+id:visit_count"
ohos:width="wrap_content"
ohos:height="wrap_content"
ohos:text="0"
ohos:text_size="20fp"
ohos:text_color="#2f54eb"
ohos:left_margin="10vp"/>
</DirectionalLayout>
<!-- 跳转按钮 -->
<Button
ohos:id="$+id:open_app_btn"
ohos:width="120vp"
ohos:height="40vp"
ohos:text="打开应用"
ohos:text_size="16fp"
ohos:background_element="$graphic:button_bg"
ohos:gravity="center"
ohos:top_margin="10vp"
ohos:layout_alignment="center"/>
</DirectionalLayout>
创建按钮背景 entry/src/main/resources/base/graphic/button_bg.xml:
xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:shape="rectangle">
<solid ohos:color="#2f54eb"/>
<corners ohos:radius="20vp"/>
</shape>
5.3 实现卡片逻辑(WidgetProvider.java)
修改 entry/src/main/java/com/example/electronatomicservice/ElectronWidget.java,实现卡片数据更新与跳转逻辑:
java
运行
package com.example.electronatomicservice;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.WidgetProvider;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import java.util.Random;
public class ElectronWidget extends WidgetProvider {
private static final HiLogLabel LABEL = new HiLogLabel(HiLog.DEBUG, 0x00001, "ElectronWidget");
private static final String ACTION_OPEN_APP = "com.example.electronatomicservice.ACTION_OPEN_APP";
@Override
public void onUpdate(Context context, Intent intent) {
super.onUpdate(context, intent);
HiLog.info(LABEL, "Widget onUpdate");
// 更新卡片数据(模拟今日访问量)
updateWidgetData(context);
// 绑定按钮点击事件
bindButtonClick(context);
}
// 更新卡片数据
private void updateWidgetData(Context context) {
Text visitCount = (Text) findComponentById(ResourceTable.Id_visit_count);
if (visitCount != null) {
int count = new Random().nextInt(1000);
visitCount.setText(String.valueOf(count));
}
}
// 绑定按钮点击事件:跳转至 Electron 应用
private void bindButtonClick(Context context) {
Button openBtn = (Button) findComponentById(ResourceTable.Id_open_app_btn);
if (openBtn != null) {
openBtn.setClickedListener(component -> {
HiLog.info(LABEL, "Open Electron app from widget");
// 启动原子化服务(即 MainAbility)
Intent intent = new Intent();
intent.setAction(ACTION_OPEN_APP);
intent.setElementName(context.getBundleName(), MainAbility.class.getName());
context.startAbility(intent);
});
}
}
}
5.4 配置卡片清单(config.json)
在 config.json 的 abilities 节点下,添加服务卡片配置:
json
"abilities": [
{
"name": "com.example.electronatomicservice.MainAbility",
// ... 原有配置
},
{
"name": "com.example.electronatomicservice.ElectronWidget",
"type": "widget",
"visible": true,
"widgetSize": ["2*2"],
"metadata": [
{
"name": "ohos.widget.provider",
"resource": "$profile:widget_profile"
}
]
}
]
创建卡片配置文件 entry/src/main/resources/base/profile/widget_profile.json:
json
{
"forms": [
{
"name": "ElectronWidget",
"description": "Electron 原子化服务卡片",
"src": "$layout:widget_layout",
"window": {
"designWidth": 720,
"autoDesignWidth": true
},
"colorMode": "auto",
"defaultDimension": "2*2",
"supportDimensions": ["2*2"],
"updateEnabled": true,
"updateDuration": 3600, // 卡片数据更新周期(秒)
"formVisibleNotify": true,
"formTempCache": true
}
]
}
5.5 验证服务卡片
- 编译鸿蒙项目,将 HAP 包安装到鸿蒙设备或模拟器;
- 在设备桌面长按空白处,选择 “添加卡片”,找到 “Electron 原子化服务卡片” 并添加;
- 卡片会显示模拟的访问量数据,点击 “打开应用” 按钮,能正常启动 Electron 应用则集成成功。
六、Electron 与鸿蒙系统的通信机制
为实现 Electron 应用与鸿蒙系统的数据交互(如卡片数据同步、系统状态获取),需打通两者的通信通道。本节将基于 node-ipc 和鸿蒙的 Intent 机制,实现双向通信。
6.1 Electron 端通信服务搭建
在 Electron 项目的 main.js 中,使用 node-ipc 启动 IPC 服务,接收鸿蒙系统的消息:
javascript
运行
const { app, BrowserWindow, ipcMain } = require('electron');
const ipc = require('node-ipc');
// 配置 IPC 服务
ipc.config.id = 'electron-harmony-ipc';
ipc.config.retry = 1500;
ipc.config.silent = true;
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
mainWindow.loadFile('dist/index.html');
// 启动 IPC 服务
startIpcServer();
}
function startIpcServer() {
ipc.serve(() => {
console.log('Electron IPC server started');
// 接收鸿蒙系统发送的消息
ipc.server.on('message', (data, socket) => {
console.log('Received message from HarmonyOS:', data);
// 处理消息(如更新应用数据)
mainWindow.webContents.send('harmony-message', data);
// 回复鸿蒙系统
ipc.server.emit(socket, 'response', { status: 'success', message: 'Message received' });
});
});
ipc.server.start();
}
// 监听渲染进程发送的消息(用于向鸿蒙系统发送数据)
ipcMain.on('send-to-harmony', (event, data) => {
console.log('Send message to HarmonyOS:', data);
// 此处需结合鸿蒙端的 IPC 客户端,实现消息发送(下文讲解)
});
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
在 Electron 渲染进程(dist/index.html)中,添加消息接收与发送逻辑:
html
预览
<!DOCTYPE html>
<html>
<body>
<h1>Electron 鸿蒙原子化服务适配Demo</h1>
<div id="message"></div>
<button onclick="sendMessageToHarmony()">向鸿蒙发送消息</button>
<script>
// 接收主进程转发的鸿蒙消息
require('electron').ipcRenderer.on('harmony-message', (event, data) => {
document.getElementById('message').innerText = `收到鸿蒙消息:${JSON.stringify(data)}`;
});
// 向鸿蒙系统发送消息
function sendMessageToHarmony() {
require('electron').ipcRenderer.send('send-to-harmony', {
type: 'data_sync',
content: 'Electron 应用数据'
});
}
</script>
</body>
</html>
6.2 鸿蒙端 IPC 客户端实现
在鸿蒙项目的 MainAbility.java 中,添加 IPC 客户端逻辑,与 Electron 的 IPC 服务通信:
java
运行
package com.example.electronatomicservice;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class MainAbility extends Ability {
private static final HiLogLabel LABEL = new HiLogLabel(HiLog.DEBUG, 0x00001, "ElectronAtomicService");
private Process electronProcess;
private Socket ipcSocket;
private OutputStreamWriter ipcWriter;
private BufferedReader ipcReader;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
HiLog.info(LABEL, "Electron atomic service started");
// 启动 Electron 应用
startElectronApp();
// 连接 Electron IPC 服务
connectIpcServer();
}
// 启动 Electron 应用(原有逻辑)
private void startElectronApp() {
// ... 原有代码
}
// 连接 Electron IPC 服务(Electron 端 IPC 服务默认端口 8080)
private void connectIpcServer() {
new Thread(() -> {
try {
// 等待 Electron IPC 服务启动(延迟 3 秒)
Thread.sleep(3000);
// 连接 Electron IPC 服务(IP 为本地回环地址,端口 8080)
ipcSocket = new Socket("127.0.0.1", 8080);
ipcWriter = new OutputStreamWriter(ipcSocket.getOutputStream());
ipcReader = new BufferedReader(new InputStreamReader(ipcSocket.getInputStream()));
HiLog.info(LABEL, "Connected to Electron IPC server");
// 向 Electron 发送消息
sendMessageToElectron("{\"type\":\"system_info\",\"content\":\"HarmonyOS 4.0\"}");
// 接收 Electron 回复的消息
String response;
while ((response = ipcReader.readLine()) != null) {
HiLog.info(LABEL, "Received response from Electron: " + response);
// 更新服务卡片数据
updateWidgetData(response);
}
} catch (IOException | InterruptedException e) {
HiLog.error(LABEL, "IPC connection failed: " + e.getMessage());
}
}).start();
}
// 向 Electron 发送消息
private void sendMessageToElectron(String message) {
try {
ipcWriter.write(message + "\n");
ipcWriter.flush();
HiLog.info(LABEL, "Sent message to Electron: " + message);
} catch (IOException e) {
HiLog.error(LABEL, "Failed to send message: " + e.getMessage());
}
}
// 更新服务卡片数据
private void updateWidgetData(String data) {
// 此处通过鸿蒙的 FormController 更新卡片数据,参考官方文档:
// https://developer.harmonyos.com/cn/docs/documentation/doc-guides/form_update-0000001157358070
}
@Override
public void onStop() {
super.onStop();
// 关闭 IPC 连接
try {
if (ipcWriter != null) ipcWriter.close();
if (ipcReader != null) ipcReader.close();
if (ipcSocket != null) ipcSocket.close();
} catch (IOException e) {
HiLog.error(LABEL, "Failed to close IPC connection: " + e.getMessage());
}
// 停止 Electron 进程(原有逻辑)
// ...
}
}
6.3 通信验证
- 重新打包 Electron 应用,更新鸿蒙项目中的
electron目录; - 安装 HAP 包并启动原子化服务;
- 鸿蒙端会向 Electron 发送系统信息,Electron 应用的页面会显示收到的消息;
- 点击 Electron 应用中的 “向鸿蒙发送消息” 按钮,鸿蒙端的日志会打印收到的消息,说明双向通信成功。
进阶方案:使用鸿蒙的
DataAbility或DistributedData实现分布式数据同步,支持多终端间的 Electron 应用数据共享。参考 鸿蒙分布式数据管理文档
七、实战案例:Electron 笔记工具适配鸿蒙原子化服务
基于以上流程,我们实现一个完整的实战案例:将一个简单的 Electron 笔记工具(支持新建、保存笔记)适配为鸿蒙原子化服务,并集成服务卡片展示笔记列表。
7.1 案例需求
- Electron 笔记工具核心功能:新建笔记、保存笔记、查看笔记列表;
- 鸿蒙服务卡片:展示最近 3 条笔记标题,点击卡片跳转至笔记工具;
- 通信功能:卡片数据与 Electron 应用实时同步。
7.2 核心代码实现
(1)Electron 笔记工具核心代码(main.js)
javascript
运行
const { app, BrowserWindow, ipcMain, dialog } = require('electron');
const ipc = require('node-ipc');
const fs = require('fs');
const path = require('path');
// 笔记存储路径
const NOTE_DIR = path.join(app.getPath('userData'), 'notes');
if (!fs.existsSync(NOTE_DIR)) fs.mkdirSync(NOTE_DIR);
// IPC 服务配置(同上节)
ipc.config.id = 'electron-note-ipc';
ipc.config.retry = 1500;
ipc.config.silent = true;
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
mainWindow.loadFile('dist/index.html');
startIpcServer();
}
// 读取笔记列表
function getNoteList() {
const files = fs.readdirSync(NOTE_DIR);
return files.map(file => {
const content = fs.readFileSync(path.join(NOTE_DIR, file), 'utf8');
return {
title: file.replace('.txt', ''),
content: content.substring(0, 30) + '...',
time: fs.statSync(path.join(NOTE_DIR, file)).mtime.toLocaleString()
};
}).sort((a, b) => new Date(b.time) - new Date(a.time)).slice(0, 3); // 取最近 3 条
}
// IPC 服务(新增笔记列表同步逻辑)
function startIpcServer() {
ipc.serve(() => {
ipc.server.on('get_note_list', (data, socket) => {
const noteList = getNoteList();
ipc.server.emit(socket, 'note_list', noteList);
});
});
ipc.server.start();
}
// 保存笔记(接收渲染进程消息)
ipcMain.on('save_note', (event, { title, content }) => {
const filePath = path.join(NOTE_DIR, `${title}.txt`);
fs.writeFileSync(filePath, content);
event.reply('save_success', true);
// 同步更新卡片数据(通过 IPC 通知鸿蒙端)
if (ipc.server.clients.length > 0) {
ipc.server.broadcast('note_updated', getNoteList());
}
});
app.whenReady().then(createWindow);
// ... 其他生命周期代码
(2)鸿蒙服务卡片数据同步代码(MainAbility.java)
java
运行
// 在 connectIpcServer 方法中,新增接收笔记列表的逻辑
private void connectIpcServer() {
new Thread(() -> {
try {
Thread.sleep(3000);
ipcSocket = new Socket("127.0.0.1", 8080);
ipcWriter = new OutputStreamWriter(ipcSocket.getOutputStream());
ipcReader = new BufferedReader(new InputStreamReader(ipcSocket.getInputStream()));
// 向 Electron 请求笔记列表
sendMessageToElectron("{\"type\":\"get_note_list\"}");
// 接收笔记列表
String response;
while ((response = ipcReader.readLine()) != null) {
HiLog.info(LABEL, "Received note list: " + response);
// 更新卡片数据
updateWidgetNoteList(response);
}
} catch (IOException | InterruptedException e) {
HiLog.error(LABEL, "IPC connection failed: " + e.getMessage());
}
}).start();
}
// 更新卡片笔记列表
private void updateWidgetNoteList(String noteListJson) {
// 解析 JSON 数据(使用 Gson 库)
Gson gson = new Gson();
List<Note> noteList = gson.fromJson(noteListJson, new TypeToken<List<Note>>(){}.getType());
// 通过 FormController 更新卡片 UI
// ... 具体实现参考鸿蒙官方文档
}
// 笔记实体类
static class Note {
private String title;
private String content;
private String time;
// getter/setter 方法
}
7.3 案例效果验证
- 安装 HAP 包后,添加服务卡片,卡片会显示最近 3 条笔记标题;
- 启动 Electron 笔记工具,新建并保存笔记,卡片数据会实时更新;
- 点击卡片中的笔记标题,会跳转至 Electron 应用并打开对应笔记。
八、常见问题排查与解决方案
8.1 Electron 应用启动失败
- 问题 1:
run.sh脚本无执行权限 → 解决方案:chmod +x run.sh; - 问题 2:鸿蒙设备缺少 Linux 运行环境 → 解决方案:确保设备系统版本为 HarmonyOS 3.0+,且已安装
libgtk-3-0等依赖; - 问题 3:权限不足 → 解决方案:在
config.json中添加ohos.permission.EXECUTE_SHELL_COMMAND权限,并在设备中授予。
8.2 服务卡片不显示或数据不更新
- 问题 1:卡片配置错误 → 解决方案:检查
config.json中的widget配置,确保src路径、widgetSize正确; - 问题 2:卡片更新周期过长 → 解决方案:在
widget_profile.json中减小updateDuration(如 60 秒); - 问题 3:IPC 通信失败 → 解决方案:检查 Electron 端 IPC 服务是否启动,端口是否被占用。
8.3 打包体积过大
- 问题:Electron 打包产物超过 10MB → 解决方案:
- 进一步裁剪依赖(如移除
node_modules中的docs、tests目录); - 使用
electron-builder的asarUnpack配置,仅解压必要文件; - 压缩 Electron 可执行文件(使用
upx工具)。
- 进一步裁剪依赖(如移除
8.4 分布式流转失败
- 问题:应用无法在多终端间流转 → 解决方案:
- 确保所有设备登录同一华为账号,且处于同一网络;
- 在
config.json中添加支持的设备类型(如tv、tablet); - 使用鸿蒙的
DistributedAbility替代ServiceAbility。
九、总结与展望
本文详细讲解了 Electron 应用适配鸿蒙原子化服务的完整流程,包括 轻量级打包、HAP 包封装、服务卡片集成、跨进程通信 四大核心环节,并通过实战案例验证了方案的可行性。通过适配,Electron 应用不仅能保留 Web 技术栈的跨平台优势,还能借助鸿蒙原子化服务的 “免安装、全场景、分布式” 特性,拓展应用的使用场景和分发渠道。
未来展望:
- 随着鸿蒙生态的完善,Electron 可能会推出官方鸿蒙适配方案,简化打包与集成流程;
- 原子化服务将支持更多终端类型(如智能手表、车机),Electron 应用可借助鸿蒙实现全场景覆盖;
- 分布式数据同步、跨终端协作等高级特性,将成为 Electron 与鸿蒙适配的重点方向。
如果你在适配过程中遇到问题,欢迎在评论区留言交流!也可参考以下官方资源进一步学习:
更多推荐








所有评论(0)