Electron鸿蒙桌面应用打包部署完全指南(含自动更新)

Electron鸿蒙桌面应用打包部署完全指南(含自动更新)

从开发到上架全流程,附完整可运行代码与配置


前言

把 Electron 应用成功运行在鸿蒙 PC 上只是第一步,打包、签名、部署、自动更新才是真正让应用走向用户的"最后一公里"。

在 Windows/macOS 上,我们有 electron-builderelectron-packager 这类成熟工具。但鸿蒙 PC 的生态还在快速演进,打包链路有不少"坑"需要踩。

本文将从零开始,带你完成以下实战目标:

  1. 配置 electron-builder 打包鸿蒙 PC 应用
  2. 生成签名证书并签名应用
  3. 实现应用自动更新(基于 electron-updater
  4. 上架鸿蒙应用市场(AppGallery)
  5. 常见打包错误与解决方案

一、技术架构总览

复制代码
┌─────────────────────────────────────────────────┐
│              Electron 应用源代码                  │
│   main.js + preload.js + renderer/             │
└──────────────────────────┬──────────────────────┘
                           │ npm run dist
┌──────────────────────────▼──────────────────────┐
│           electron-builder 打包阶段               │
│   1. 编译原生模块(.node 插件)                   │
│   2. 打包 Electron 二进制                       │
│   3. 生成安装包(.exe / .appimage)             │
└──────────────────────────┬──────────────────────┘
                           │ 签名
┌──────────────────────────▼──────────────────────┐
│           鸿蒙应用签名(.p12 证书)               │
│   使用 hmos-sign 或手动 jarsigner                │
└──────────────────────────┬──────────────────────┘
                           │ 发布
┌──────────────────────────▼──────────────────────┐
│           鸿蒙应用市场 / 自动更新服务器            │
│   app-update.yml + GitHub Releases              │
└─────────────────────────────────────────────────┘

二、环境准备

2.1 工具清单

工具 版本 用途
Electron 34.x 主框架
electron-builder 26.x 打包工具
electron-updater 6.x 自动更新
DevEco Studio 5.0.5+ 鸿蒙 SDK
hmos-sign 1.0.0+ 鸿蒙应用签名

2.2 安装依赖

bash 复制代码
# 初始化项目
mkdir electron-hmos-packaging && cd electron-hmos-packaging
npm init -y

# 安装 Electron(鸿蒙定制版)
npm install electron --save-dev

# 安装打包工具
npm install electron-builder --save-dev

# 安装自动更新
npm install electron-updater --save

# 安装鸿蒙签名工具
npm install hmos-sign --save-dev

三、配置 electron-builder

3.1 基础配置(package.json)

json 复制代码
{
  "name": "electron-hmos-demo",
  "version": "1.0.0",
  "description": "Electron 鸿蒙桌面应用示例",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "dist": "electron-builder --config electron-builder.yml",
    "dist:hmos": "electron-builder --config electron-builder.hmos.yml"
  },
  "devDependencies": {
    "electron": "^34.0.0",
    "electron-builder": "^26.0.0"
  },
  "build": {
    "appId": "com.example.electronhmos",
    "productName": "Electron鸿蒙示例",
    "directories": {
      "output": "dist/"
    }
  }
}

3.2 鸿蒙专用配置(electron-builder.hmos.yml)

yaml 复制代码
appId: com.example.electronhmos
productName: Electron鸿蒙示例
directories:
  output: dist/

# 鸿蒙 PC 平台配置
hmos:
  target: 
    - target: hmos
      arch:
        - x64
        - arm64
  icon: resources/icon.png
  
  # 签名配置
  sign: 
    certificate: certificates/hmos.p12
    password: "your-cert-password"
    provisioningProfile: certificates/hmos.mobileprovision"
  
  # 安装包信息
  installer:
    name: "Electron鸿蒙示例"
    categories:
      - Utility
    mimeTypes:
      - application/x-extension-html
    
# 文件关联
fileAssociations:
  - ext: html
    name: HTML 文件
    role: Editor

# 自动更新配置
publish:
  - provider: generic
    url: https://update.example.com/electron-hmos/
    channel: latest.yml

四、主进程配置(main.js)

javascript 复制代码
// main.js
const { app, BrowserWindow, ipcMain } = require('electron');
const { autoUpdater } = require('electron-updater');
const path = require('path');

let mainWindow;

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

  // 加载应用
  if (process.env.NODE_ENV === 'development') {
    mainWindow.loadURL('http://localhost:3000');
    mainWindow.webContents.openDevTools();
  } else {
    mainWindow.loadFile('renderer/index.html');
  }

  // 自动更新事件
  setupAutoUpdater();
}

// 自动更新配置
function setupAutoUpdater() {
  // 设置更新服务器地址
  autoUpdater.setFeedURL({
    provider: 'generic',
    url: 'https://update.example.com/electron-hmos/'
  });

  // 检查更新
  autoUpdater.checkForUpdatesAndNotify();

  // 更新事件监听
  autoUpdater.on('checking-for-update', () => {
    console.log('正在检查更新...');
    mainWindow.webContents.send('update-status', 'checking');
  });

  autoUpdater.on('update-available', (info) => {
    console.log('发现新版本:', info.version);
    mainWindow.webContents.send('update-status', 'available', info);
  });

  autoUpdater.on('update-not-available', () => {
    console.log('当前已是最新版本');
    mainWindow.webContents.send('update-status', 'not-available');
  });

  autoUpdater.on('download-progress', (progressObj) => {
    console.log(`下载进度: ${progressObj.percent}%`);
    mainWindow.webContents.send('update-progress', progressObj);
  });

  autoUpdater.on('update-downloaded', (info) => {
    console.log('更新包下载完成,将在下次启动时安装');
    mainWindow.webContents.send('update-status', 'downloaded', info);
    
    // 提示用户重启应用
    setTimeout(() => {
      if (confirm('新版本已下载完成,是否现在重启应用?')) {
        autoUpdater.quitAndInstall();
      }
    }, 3000);
  });

  autoUpdater.on('error', (err) => {
    console.error('自动更新错误:', err);
    mainWindow.webContents.send('update-status', 'error', err);
  });
}

app.whenReady().then(() => {
  createWindow();
  
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

五、预加载脚本(preload.js)

javascript 复制代码
// preload.js
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  // 检查更新
  checkForUpdates: () => ipcRenderer.invoke('check-for-updates'),
  
  // 更新状态监听
  onUpdateStatus: (callback) => ipcRenderer.on('update-status', callback),
  onUpdateProgress: (callback) => ipcRenderer.on('update-progress', callback),
  
  // 安装更新
  installUpdate: () => ipcRenderer.invoke('install-update'),
  
  // 获取应用版本
  getAppVersion: () => ipcRenderer.invoke('get-app-version')
});

六、渲染进程(index.html)

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Electron 鸿蒙应用 - 自动更新示例</title>
  <style>
    body {
      font-family: 'HarmonyOS Sans', sans-serif;
      padding: 20px;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      color: white;
      min-height: 100vh;
    }
    .container {
      max-width: 800px;
      margin: 0 auto;
      background: rgba(255,255,255,0.1);
      padding: 30px;
      border-radius: 15px;
      backdrop-filter: blur(10px);
    }
    .update-status {
      margin: 20px 0;
      padding: 15px;
      border-radius: 8px;
      background: rgba(0,0,0,0.2);
    }
    .progress-bar {
      width: 100%;
      height: 20px;
      background: rgba(255,255,255,0.2);
      border-radius: 10px;
      overflow: hidden;
      margin: 10px 0;
    }
    .progress-fill {
      height: 100%;
      background: linear-gradient(90deg, #00c9ff 0%, #92fe9d 100%);
      transition: width 0.3s ease;
    }
    button {
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      color: white;
      border: none;
      padding: 12px 24px;
      border-radius: 8px;
      cursor: pointer;
      font-size: 16px;
      margin: 5px;
    }
    button:hover {
      opacity: 0.9;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>🚀 Electron 鸿蒙应用</h1>
    <p>版本: <span id="version">加载中...</span></p>
    
    <div class="update-status">
      <h3>自动更新状态</h3>
      <div id="status">正在检查更新...</div>
      <div class="progress-bar" id="progressBar" style="display:none;">
        <div class="progress-fill" id="progressFill"></div>
      </div>
      <div id="progressText"></div>
    </div>
    
    <div>
      <button onclick="checkForUpdates()">手动检查更新</button>
      <button onclick="installUpdate()" id="installBtn" style="display:none;">立即安装更新</button>
    </div>
  </div>

  <script>
    // 获取应用版本
    window.electronAPI.getAppVersion().then(version => {
      document.getElementById('version').textContent = version;
    });
    
    // 监听更新状态
    window.electronAPI.onUpdateStatus((event, status, data) => {
      const statusEl = document.getElementById('status');
      const installBtn = document.getElementById('installBtn');
      
      switch(status) {
        case 'checking':
          statusEl.textContent = '正在检查更新...';
          break;
        case 'available':
          statusEl.textContent = `发现新版本: ${data.version}`;
          break;
        case 'not-available':
          statusEl.textContent = '当前已是最新版本';
          break;
        case 'downloaded':
          statusEl.textContent = '更新包下载完成,请重启应用';
          installBtn.style.display = 'inline-block';
          break;
        case 'error':
          statusEl.textContent = `更新错误: ${data}`;
          break;
      }
    });
    
    // 监听下载进度
    window.electronAPI.onUpdateProgress((event, progress) => {
      const progressBar = document.getElementById('progressBar');
      const progressFill = document.getElementById('progressFill');
      const progressText = document.getElementById('progressText');
      
      progressBar.style.display = 'block';
      progressFill.style.width = `${progress.percent}%`;
      progressText.textContent = `下载进度: ${Math.round(progress.percent)}%`;
    });
    
    // 手动检查更新
    function checkForUpdates() {
      window.electronAPI.checkForUpdates();
    }
    
    // 安装更新
    function installUpdate() {
      window.electronAPI.installUpdate();
    }
  </script>
</body>
</html>

七、鸿蒙应用签名

7.1 生成签名证书

bash 复制代码
# 使用 keytool 生成 .p12 证书
keytool -genkeypair \
  -alias electron-hmos \
  -keyalg RSA \
  -keysize 2048 \
  -validity 3650 \
  -keystore certificates/hmos.p12 \
  -storetype PKCS12 \
  -dname "CN=Your Name, OU=Development, O=Your Company, L=City, ST=Province, C=CN" \
  -storepass your-cert-password

7.2 配置签名(electron-builder.hmos.yml)

yaml 复制代码
hmos:
  sign:
    certificate: certificates/hmos.p12
    password: "your-cert-password"
    provisioningProfile: certificates/hmos.mobileprovision"

7.3 手动签名(备用方案)

bash 复制代码
# 如果自动签名失败,可以手动签名
jarsigner -verbose \
  -sigalg SHA256withRSA \
  -digestalg SHA-256 \
  -keystore certificates/hmos.p12 \
  -storepass your-cert-password \
  dist/Electron鸿蒙示例-1.0.0.hmos \
  electron-hmos

八、打包执行

8.1 执行打包命令

bash 复制代码
# 打包鸿蒙 PC 版本
npm run dist:hmos

输出文件:

复制代码
dist/
├── Electron鸿蒙示例-1.0.0-hmos-x64.hmos
├── Electron鸿蒙示例-1.0.0-hmos-arm64.hmos
├── latest.yml
└── builder-effective-config.yaml

8.2 常见打包错误与解决

错误 原因 解决方案
Cannot find module 'electron' Electron 未正确安装 rm -rf node_modules && npm install
hmos target not supported electron-builder 版本过低 升级到 26.x+
Certificate not found 证书路径错误 检查 electron-builder.hmos.yml 中的证书路径
Signing failed 证书密码错误 确认密码正确,或重新生成证书
Auto-updater error 更新服务器配置错误 检查 autoUpdater.setFeedURL() 配置

九、上架鸿蒙应用市场

9.1 准备材料

  1. 应用安装包(.hmos 文件)
  2. 应用图标(512x512 PNG)
  3. 应用截图(1280x720 或 1920x1080)
  4. 应用描述(中文,200字以内)
  5. 隐私政策(必须提供)

9.2 提交流程

  1. 登录 鸿蒙应用市场开发者后台
  2. 创建新应用,填写基本信息
  3. 上传安装包和素材
  4. 提交审核(通常需要 3-5 个工作日)
  5. 审核通过后上架

十、自动更新服务器搭建

10.1 使用 GitHub Releases

yaml 复制代码
# electron-builder.hmos.yml
publish:
  - provider: github
    owner: your-github-username
    repo: electron-hmos-demo
    token: ${{ secrets.GITHUB_TOKEN }}

10.2 使用私有服务器

bash 复制代码
# 1. 在服务器上创建更新目录
mkdir -p /var/www/update/electron-hmos/

# 2. 上传打包文件
scp dist/* user@server:/var/www/update/electron-hmos/

# 3. 确保 latest.yml 可访问
curl https://update.example.com/electron-hmos/latest.yml

十一、总结

本文完整介绍了 Electron 鸿蒙桌面应用的打包、签名、部署和自动更新全流程。核心要点:

  1. 配置 electron-builder - 使用鸿蒙专用配置
  2. 签名应用 - 生成 .p12 证书并配置
  3. 自动更新 - 使用 electron-updater
  4. 上架市场 - 准备材料并提交审核
  5. 更新服务器 - GitHub Releases 或私有服务器

参考资料

相关推荐
哆哆啦001 小时前
CSS 选择器优先级计算规则
前端·javascript·css3
三声三视1 小时前
Electron for 鸿蒙PC:用 Node-API 打通原生系统调用,告别“Web 孤岛
electron·harmonyos·桌面应用·鸿蒙
zhoumeina991 小时前
设计器模版底图,一直渲染错误,是因为第一张图变形后内存中图片数据被改了,其他尺码一直错误
java·前端·javascript
小粉粉hhh1 小时前
Node.js(四)——npm与包
前端·npm·node.js
雨落在了我的手上1 小时前
初识java(四):程序逻辑控制
java·开发语言·前端
UXbot1 小时前
Vibecoding 工具如何一次性生成 Web + iOS + Android 三端 APP?功能架构深度解读
android·前端·ui·ios·交互·软件构建·ai编程
AlbertZein1 小时前
跨项目设计模式(二):策略模式——从 ImageKnife 的加载器到 HMRouter 的生命周期
harmonyos
AlbertZein1 小时前
跨项目设计模式(一):单例模式在鸿蒙框架中的 6 种实现
harmonyos
前端不太难1 小时前
鸿蒙 App 的登录 / 订单 / 支付系统拆解
华为·状态模式·harmonyos