前言

鸿蒙 OS(HarmonyOS)的 “分布式架构” 与 “一次开发多端部署” 特性,正成为生态扩张的核心竞争力。而 Electron 作为前端跨端开发的 “利器”,凭借 HTML/CSS/JS 技术栈的低门槛和丰富生态,让开发者能快速构建桌面应用。对于前端开发者而言,无需学习 ArkTS 原生开发,通过 Electron 即可快速适配鸿蒙系统,这无疑是切入鸿蒙生态的 “捷径”。

本文将聚焦鸿蒙与 Electron 的结合实践,从核心原理到项目落地,配套可直接运行的代码案例,涵盖环境搭建、功能开发、鸿蒙适配、调试部署全流程,帮助前端开发者零成本实现鸿蒙跨端应用开发。

一、核心原理:鸿蒙与 Electron 的适配逻辑

1. 底层兼容基础

鸿蒙 OS 3.0 及以上版本内置 “Linux 容器” 和 “兼容层”,支持运行 Linux 原生应用。而 Electron 的本质是 “Chromium 内核 + Node.js 运行时”,其 Linux 版本可通过鸿蒙的 Linux 兼容层直接运行,无需修改 Electron 核心源码。

2. 核心适配要点

  • 架构匹配:鸿蒙设备主流为 x64 架构,需将 Electron 应用打包为 Linux-x64 版本;
  • 权限配置:鸿蒙设备需开启开发者模式与 Linux 环境兼容开关;
  • 通信安全:关闭 Electron 的上下文隔离(contextIsolation: false),确保 Node.js API 在鸿蒙环境正常调用;
  • 样式适配:遵循鸿蒙扁平化设计风格,优化窗口样式与交互体验。

二、环境搭建:零踩坑配置步骤

1. 必备环境清单

工具 / 环境 版本要求 作用
鸿蒙 OS 3.0 及以上(PC / 平板 / 手机) 应用运行目标设备
开发机系统 Windows 10+/macOS 12+ 代码编写与打包
Node.js 16.x LTS / 18.x LTS Electron 运行依赖
Electron 22.x(稳定版) 跨端应用开发框架
Electron-packager 最新版 应用打包工具
VS Code 任意稳定版 代码编辑(推荐安装 Electron 插件)
DevEco Studio 4.0+(可选) 鸿蒙设备调试与 HAP 包打包

2. 环境安装命令

bash

运行

# 1. 全局安装Electron与打包工具
npm install -g electron@22.3.2 electron-packager

# 2. 验证安装
electron -v  # 输出 v22.3.2 表示成功
electron-packager -v  # 输出版本号表示成功

3. 鸿蒙设备配置

  1. 进入鸿蒙设备「设置」→「系统和更新」→「开发者选项」(连续点击版本号 7 次激活);
  2. 开启「USB 调试」「允许安装未知来源应用」「Linux 环境兼容」(不同设备路径略有差异)。

三、实战开发:鸿蒙 Electron 应用完整实现

本节将开发一个 “鸿蒙设备文件管理器”,支持文件列表展示、文件夹切换、文件大小查看功能,配套完整代码与注释。

1. 项目初始化

bash

运行

# 1. 创建项目目录
mkdir harmony-electron-file-manager
cd harmony-electron-file-manager

# 2. 初始化package.json
npm init -y

# 3. 安装依赖
npm install electron@22.3.2 --save
npm install nodemon --save-dev  # 热重载开发依赖

2. 配置 package.json

json

{
  "name": "harmony-electron-file-manager",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "nodemon --exec electron .",  // 热重载启动
    "package": "electron-packager . harmony-file-manager --platform=linux --arch=x64 --out=dist"  // 打包Linux-x64版本
  },
  "devDependencies": {
    "nodemon": "^3.1.0"
  },
  "dependencies": {
    "electron": "^22.3.2"
  }
}

3. 核心代码实现

(1)主进程:main.js(窗口配置 + 文件操作逻辑)

javascript

运行

const { app, BrowserWindow, ipcMain } = require('electron');
const fs = require('fs');
const path = require('path');

let mainWindow;

// 创建应用窗口
function createWindow() {
  mainWindow = new BrowserWindow({
    width: 1000,
    height: 700,
    title: '鸿蒙文件管理器',
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,  // 鸿蒙兼容必需:关闭上下文隔离
      preload: path.join(__dirname, 'preload.js')
    },
    // 鸿蒙样式适配:扁平化窗口
    frame: false,
    titleBarStyle: 'hiddenInset'
  });

  // 加载UI页面
  mainWindow.loadFile('index.html');

  // 打开开发者工具(调试用)
  mainWindow.webContents.openDevTools();

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

// 监听文件列表查询请求
ipcMain.on('get-file-list', (event, currentPath) => {
  try {
    // 读取当前目录下的文件/文件夹
    const files = fs.readdirSync(currentPath, { withFileTypes: true });
    const fileList = files.map(file => {
      const filePath = path.join(currentPath, file.name);
      const stats = fs.statSync(filePath);
      return {
        name: file.name,
        isDirectory: file.isDirectory(),
        size: file.isFile() ? formatFileSize(stats.size) : '-',
        mtime: stats.mtime.toLocaleString(),
        path: filePath
      };
    });
    // 向渲染进程返回结果
    event.reply('file-list-reply', { success: true, fileList, currentPath });
  } catch (error) {
    event.reply('file-list-reply', { success: false, message: '读取目录失败:' + error.message });
  }
});

// 监听窗口控制事件(关闭/最小化)
ipcMain.on('window-control', (event, action) => {
  switch (action) {
    case 'close':
      mainWindow.close();
      break;
    case 'minimize':
      mainWindow.minimize();
      break;
  }
});

// 文件大小格式化工具
function formatFileSize(bytes) {
  if (bytes < 1024) return bytes + ' B';
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
  return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
}

// 应用就绪后创建窗口
app.whenReady().then(createWindow);

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

// 激活应用时重建窗口(macOS)
app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
(2)预加载脚本:preload.js(通信桥接)

javascript

运行

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

// 向渲染进程暴露安全API
contextBridge.exposeInMainWorld('electronAPI', {
  // 获取文件列表
  getFileList: (path) => {
    return new Promise((resolve) => {
      ipcRenderer.send('get-file-list', path);
      ipcRenderer.once('file-list-reply', (event, data) => {
        resolve(data);
      });
    });
  },
  // 窗口控制(关闭/最小化)
  windowControl: (action) => {
    ipcRenderer.send('window-control', action);
  }
});
(3)渲染进程:index.html(UI 界面 + 交互)

html

预览

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>鸿蒙文件管理器</title>
  <style>
    /* 鸿蒙扁平化风格适配 */
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      font-family: "HarmonyOS Sans SC", sans-serif;
    }
    body {
      background-color: #f5f5f7;
      color: #1d1d1f;
    }
    /* 窗口头部(鸿蒙风格) */
    .window-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 12px 20px;
      background-color: #ffffff;
      border-bottom: 1px solid #e5e5e7;
    }
    .window-title {
      font-size: 18px;
      font-weight: 500;
    }
    .control-buttons {
      display: flex;
      gap: 12px;
    }
    .control-btn {
      width: 32px;
      height: 32px;
      border: none;
      background: transparent;
      cursor: pointer;
      border-radius: 50%;
      transition: background-color 0.2s;
      font-size: 16px;
    }
    .control-btn:hover {
      background-color: #f0f0f2;
    }
    /* 路径导航栏 */
    .path-nav {
      padding: 16px 20px;
      background-color: #ffffff;
      border-bottom: 1px solid #e5e5e7;
    }
    .path-btn {
      padding: 6px 12px;
      margin-right: 8px;
      border: 1px solid #e5e5e7;
      border-radius: 6px;
      background: transparent;
      cursor: pointer;
      transition: background-color 0.2s;
    }
    .path-btn:hover {
      background-color: #f5f5f7;
    }
    /* 文件列表区域 */
    .file-list {
      padding: 20px;
    }
    .file-item {
      display: flex;
      align-items: center;
      padding: 12px 16px;
      margin-bottom: 8px;
      background-color: #ffffff;
      border-radius: 8px;
      cursor: pointer;
      transition: background-color 0.2s;
    }
    .file-item:hover {
      background-color: #f0f0f2;
    }
    .file-icon {
      margin-right: 16px;
      font-size: 24px;
    }
    .file-folder {
      color: #007aff;
    }
    .file-file {
      color: #86868b;
    }
    .file-name {
      flex: 1;
      font-size: 16px;
    }
    .file-info {
      display: flex;
      gap: 32px;
      color: #86868b;
      font-size: 14px;
    }
    /* 加载状态与错误提示 */
    .loading, .error {
      padding: 40px;
      text-align: center;
      color: #86868b;
      font-size: 16px;
    }
  </style>
</head>
<body>
  <!-- 窗口头部 -->
  <div class="window-header">
    <div class="window-title">鸿蒙文件管理器</div>
    <div class="control-buttons">
      <button class="control-btn" onclick="window.electronAPI.windowControl('minimize')">—</button>
      <button class="control-btn" onclick="window.electronAPI.windowControl('close')">✕</button>
    </div>
  </div>

  <!-- 路径导航 -->
  <div class="path-nav" id="pathNav">
    <button class="path-btn" onclick="loadPath('/')">/(根目录)</button>
  </div>

  <!-- 文件列表 -->
  <div class="file-list" id="fileList">
    <div class="loading">加载中...</div>
  </div>

  <script>
    // 初始化:加载根目录文件
    window.addEventListener('DOMContentLoaded', () => {
      loadPath('/');
    });

    // 加载指定路径的文件列表
    async function loadPath(path) {
      const fileListEl = document.getElementById('fileList');
      fileListEl.innerHTML = '<div class="loading">加载中...</div>';

      try {
        // 调用主进程API获取文件列表
        const result = await window.electronAPI.getFileList(path);
        if (!result.success) {
          fileListEl.innerHTML = `<div class="error">${result.message}</div>`;
          return;
        }

        // 渲染文件列表
        renderFileList(result.fileList, result.currentPath);
        // 更新路径导航
        updatePathNav(result.currentPath);
      } catch (error) {
        fileListEl.innerHTML = `<div class="error">加载失败:${error.message}</div>`;
      }
    }

    // 渲染文件列表
    function renderFileList(fileList, currentPath) {
      const fileListEl = document.getElementById('fileList');
      if (fileList.length === 0) {
        fileListEl.innerHTML = '<div class="loading">当前目录无文件</div>';
        return;
      }

      let html = '';
      fileList.forEach(file => {
        html += `
          <div class="file-item" onclick="${file.isDirectory ? `loadPath('${file.path}')` : ''}">
            <div class="file-icon ${file.isDirectory ? 'file-folder' : 'file-file'}">
              ${file.isDirectory ? '📂' : '📄'}
            </div>
            <div class="file-name">${file.name}</div>
            <div class="file-info">
              <div>${file.size}</div>
              <div>${file.mtime}</div>
            </div>
          </div>
        `;
      });
      fileListEl.innerHTML = html;
    }

    // 更新路径导航
    function updatePathNav(currentPath) {
      const pathNavEl = document.getElementById('pathNav');
      const paths = currentPath.split('/').filter(Boolean);
      
      let navHtml = '<button class="path-btn" onclick="loadPath(\'/')">/(根目录)</button>';
      let currentPathTemp = '';
      
      paths.forEach((path, index) => {
        currentPathTemp += '/' + path;
        navHtml += `<button class="path-btn" onclick="loadPath('${currentPathTemp}')">${path}</button>`;
      });
      
      pathNavEl.innerHTML = navHtml;
    }
  </script>
</body>
</html>

4. 代码核心说明

  • 主进程(main.js):负责窗口创建、文件系统操作(Node.js fs 模块)、与渲染进程通信,同时配置鸿蒙兼容必需的参数;
  • 预加载脚本(preload.js):通过contextBridge暴露安全 API,避免渲染进程直接访问 Node.js API 带来的风险;
  • 渲染进程(index.html):采用鸿蒙扁平化设计风格,实现文件列表展示、路径导航、窗口控制等交互功能,通过暴露的electronAPI与主进程通信;
  • 鸿蒙适配关键:关闭上下文隔离、打包 Linux-x64 架构、窗口样式适配鸿蒙设计规范。

四、调试与部署:鸿蒙设备运行步骤

1. 本地调试

bash

运行

# 项目根目录执行,启动热重载开发模式
npm start

启动后将打开应用窗口,展示开发机的文件系统,可调试 UI 样式与功能逻辑。

2. 鸿蒙设备部署

(1)打包 Linux-x64 版本

bash

运行

# 执行打包命令,生成鸿蒙兼容的应用包
npm run package

打包完成后,项目根目录会生成dist/harmony-file-manager-linux-x64文件夹,包含可直接运行的应用文件。

(2)传输应用到鸿蒙设备
  • 方式 1:USB 传输:通过 USB 数据线连接开发机与鸿蒙设备,拷贝harmony-file-manager-linux-x64文件夹到设备(如 “文档” 目录);
  • 方式 2:网络共享:开发机开启文件夹共享,鸿蒙设备通过 “文件管理” 访问并下载应用包。
(3)鸿蒙设备运行应用
  1. 打开鸿蒙设备 “终端” 应用(开发者模式下可搜索找到);
  2. 进入应用目录(以拷贝到 “文档” 为例):

    bash

    运行

    cd /home/user/Documents/harmony-file-manager-linux-x64
    
  3. 赋予执行权限:

    bash

    运行

    chmod +x harmony-file-manager
    
  4. 启动应用:

    bash

    运行

    ./harmony-file-manager
    

启动成功后,即可在鸿蒙设备上使用文件管理器,支持浏览目录、查看文件信息等功能。

3. 常见问题排查

问题现象 解决方案
应用无法启动,提示 “权限不足” 执行chmod +x harmony-file-manager赋予权限
启动后白屏无内容 检查 main.js 中contextIsolation: false配置
无法读取文件,提示 “权限 denied” 鸿蒙设备需开启 “文件访问权限”(开发者选项中)
应用闪退 确认鸿蒙 OS 版本≥3.0,低版本不支持 Linux 兼容层

五、进阶优化:鸿蒙特性深度适配

1. 调用鸿蒙系统通知

通过electron-harmony-adapter插件实现鸿蒙原生通知功能:

bash

运行

# 安装插件
npm install electron-harmony-adapter --save

在 main.js 中添加通知逻辑:

javascript

运行

const { HarmonyAdapter } = require('electron-harmony-adapter');
const path = require('path');

function createWindow() {
  // ... 原有窗口配置 ...
  const harmonyAdapter = new HarmonyAdapter(mainWindow);

  // 示例:文件加载完成后发送通知
  ipcMain.on('file-loaded', () => {
    harmonyAdapter.showNotification({
      title: '文件管理器',
      body: '文件列表加载完成',
      icon: path.join(__dirname, 'icon.png')
    });
  });
}

2. 适配鸿蒙深色模式

在 index.html 中添加深色模式检测与适配:

javascript

运行

// 深色模式适配
function adaptDarkMode() {
  const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
  if (isDark) {
    document.body.classList.add('dark-mode');
    document.documentElement.style.setProperty('--bg-color', '#1a1a1a');
    document.documentElement.style.setProperty('--card-bg', '#2c2c2e');
  }
}

// 初始化适配+监听模式切换
adaptDarkMode();
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', adaptDarkMode);

添加深色模式 CSS 样式:

css

.dark-mode {
  --bg-color: #1a1a1a;
  --card-bg: #2c2c2e;
  background-color: var(--bg-color);
  color: #f5f5f7;
}
.dark-mode .window-header, .dark-mode .path-nav, .dark-mode .file-item {
  background-color: var(--card-bg);
  border-color: #3a3a3c;
}

六、总结与展望

通过本文的实战案例,前端开发者可零成本实现鸿蒙跨端应用开发,核心优势在于:

  1. 技术栈复用:无需学习 ArkTS,HTML/CSS/JS 即可开发鸿蒙应用;
  2. 开发效率高:Electron 生态丰富,可直接复用 npm 包与现有代码;
  3. 部署成本低:通过 Linux 兼容层快速适配,无需重构应用。

未来,随着鸿蒙 OS 对 Linux 生态的进一步优化,Electron 与鸿蒙的结合将覆盖更多场景(如办公软件、开发工具、娱乐应用等)。对于前端开发者而言,这是切入国产操作系统生态的绝佳机会,既能积累跨端开发经验,又能抢占鸿蒙生态红利。

如果本文对你有帮助,欢迎点赞、收藏、关注!后续将分享 Electron+Vue/React 适配鸿蒙、鸿蒙 HAP 包打包发布等进阶内容,敬请期待~

文末标签

#鸿蒙OS #Electron #跨端开发 #前端开发 #鸿蒙应用开发 #代码实战 #桌面应用

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

Logo

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

更多推荐