第 8 章:应用打包与跨平台发布

开发完成后,你需要将应用打包成可执行文件,分发给用户。本章将学习使用 electron-builder 进行应用打包, 配置 Windows 和 macOS 的打包选项,以及代码签名和发布流程。

8.1 electron-builder 简介

electron-builder 是目前最流行的 Electron 应用打包工具,它可以将你的应用打包成 Windows 的 .exe/.msi、 macOS 的 .dmg/.pkg、Linux 的 .AppImage/.deb 等格式。

💡给前端开发者的建议

把 electron-builder 想象成 Webpack/Vite 的打包阶段,只不过它打包的不是网页,而是完整的桌面应用。 配置方式也很相似——通过配置文件定义入口、输出、插件等。

安装 electron-builder

bash
# 作为开发依赖安装
npm install electron-builder --save-dev

# 或者使用 yarn
yarn add electron-builder --dev

8.2 配置 electron-builder

electron-builder 支持多种配置方式:package.json 中的 build 字段、独立的 electron-builder.yml 文件、 或通过命令行参数。推荐使用独立的 YAML 配置文件,更清晰易维护。

基础配置(electron-builder.yml)

yaml
# 应用基本信息
appId: com.yourcompany.yourapp
productName: "RPA Desktop Assistant"
copyright: "Copyright © 2024 Your Company"

# 打包输出目录
directories:
  output: dist
  buildResources: build

# 文件包含规则
files:
  - "out/**/*"
  - "node_modules/**/*"
  - "package.json"
  - "!node_modules/.cache"
  - "!**/*.map"

# 额外资源(不打包到 asar 中)
extraResources:
  - from: "assets/"
    to: "assets"
  - from: "templates/"
    to: "templates"

# ASAR 配置
asar: true
asarUnpack:
  - "node_modules/sharp/**/*"
  - "node_modules/@nut-tree/**/*"

# Windows 配置
win:
  target:
    - target: nsis
      arch:
        - x64
        - ia32
    - target: portable
      arch:
        - x64
  icon: build/icon.ico
  publisherName: "Your Company"
  verifyUpdateCodeSignature: false

# macOS 配置
mac:
  target:
    - target: dmg
      arch:
        - x64
        - arm64
    - target: zip
      arch:
        - x64
        - arm64
  icon: build/icon.icns
  category: public.app-category.productivity
  hardenedRuntime: true
  gatekeeperAssess: false

# Linux 配置
linux:
  target:
    - AppImage
    - deb
  icon: build/icons
  category: Office

# NSIS 安装程序配置(Windows)
nsis:
  oneClick: false
  allowToChangeInstallationDirectory: true
  createDesktopShortcut: always
  createStartMenuShortcut: true
  shortcutName: "RPA Assistant"
  uninstallDisplayName: "RPA Desktop Assistant"
  license: "LICENSE.txt"
  artifactName: "${productName}-Setup-${version}.${ext}"

# DMG 配置(macOS)
dmg:
  sign: false
  contents:
    - x: 130
      y: 220
    - x: 410
      y: 220
      type: link
      path: "/Applications"

package.json 脚本配置

json
{
  "name": "rpa-desktop-assistant",
  "version": "1.0.0",
  "main": "out/main/index.js",
  "scripts": {
    "dev": "electron-vite dev",
    "build": "electron-vite build",
    "preview": "electron-vite preview",
    "pack": "electron-builder --dir",
    "dist": "electron-builder",
    "dist:win": "electron-builder --win",
    "dist:mac": "electron-builder --mac",
    "dist:linux": "electron-builder --linux",
    "postinstall": "electron-builder install-app-deps"
  },
  "build": {
    "extends": "./electron-builder.yml"
  }
}

8.3 Windows 打包详解

Windows 是最常用的桌面平台,electron-builder 支持多种 Windows 安装包格式。

格式扩展名特点适用场景
NSIS.exe标准安装程序,支持自定义向导大多数场景
Portable.exe免安装,直接运行U盘携带、快速试用
MSI.msi企业部署、组策略安装企业环境
7z/zip.7z/.zip压缩包,无安装向导高级用户

Windows 图标配置

bash
# 准备图标文件
# Windows 图标:256x256 像素的 .ico 文件
# 可以使用在线工具将 PNG 转换为 ICO
# 推荐工具:https://convertio.co/zh/png-ico/

# 图标文件路径(在 electron-builder.yml 中配置)
# win.icon: build/icon.ico

# 多尺寸图标(推荐包含 16x16, 32x32, 48x48, 256x256)
# 可以使用 icotools 或 Resource Hacker 创建

Windows 代码签名

未签名的 Windows 应用会显示"Windows 已保护你的电脑"警告,影响用户体验。 代码签名需要购买证书(约 ¥1000-3000/年)。

yaml
# electron-builder.yml - 代码签名配置
win:
  certificateFile: "build/certificate.p12"
  certificatePassword: "your-password"
  # 或者使用环境变量
  # certificatePassword: ${env.CERT_PASSWORD}

# 环境变量方式(更安全)
# 在 CI/CD 中设置环境变量
# WIN_CSC_LINK: base64 编码的证书
# WIN_CSC_KEY_PASSWORD: 证书密码
💡免费代码签名方案
  • Certum 开源开发者证书:约 €69/年,验证身份较简单
  • Let's Encrypt 不适用:不支持代码签名
  • 测试阶段:可以先不签名,正式发布前再购买证书

8.4 macOS 打包详解

macOS 打包相对复杂,需要处理代码签名、公证(Notarization)等流程。

macOS 图标配置

bash
# macOS 图标需要 .icns 格式
# 1. 准备 1024x1024 的 PNG 图标
# 2. 使用 iconutil 或在线工具转换为 .icns

# 使用 iconutil(macOS 自带)
mkdir MyIcon.iconset
sips -z 16 16     icon.png --out MyIcon.iconset/icon_16x16.png
sips -z 32 32     icon.png --out MyIcon.iconset/icon_16x16@2x.png
sips -z 32 32     icon.png --out MyIcon.iconset/icon_32x32.png
sips -z 64 64     icon.png --out MyIcon.iconset/icon_32x32@2x.png
sips -z 128 128   icon.png --out MyIcon.iconset/icon_128x128.png
sips -z 256 256   icon.png --out MyIcon.iconset/icon_128x128@2x.png
sips -z 256 256   icon.png --out MyIcon.iconset/icon_256x256.png
sips -z 512 512   icon.png --out MyIcon.iconset/icon_256x256@2x.png
sips -z 512 512   icon.png --out MyIcon.iconset/icon_512x512.png
sips -z 1024 1024 icon.png --out MyIcon.iconset/icon_512x512@2x.png

iconutil -c icns MyIcon.iconset -o build/icon.icns
rm -rf MyIcon.iconset

macOS 代码签名与公证

macOS 10.15+ 要求所有分发的应用必须经过公证(Notarization),否则无法运行。 这需要 Apple Developer 账号(¥688/年)。

yaml
# electron-builder.yml - macOS 签名配置
mac:
  icon: build/icon.icns
  category: public.app-category.productivity
  # 启用强化运行时(Notarization 必需)
  hardenedRuntime: true
  gatekeeperAssess: false
  # 权限声明
  entitlements: build/entitlements.mac.plist
  entitlementsInherit: build/entitlements.mac.plist

# 公证配置(使用 notarize-cli 或 electron-notarize)
# 需要在环境变量中设置 Apple ID 和 App 专用密码
# APPLE_ID: your-apple-id@example.com
# APPLE_APP_SPECIFIC_PASSWORD: xxxx-xxxx-xxxx-xxxx
# APPLE_TEAM_ID: XXXXXXXXXX
xml





  
  com.apple.security.cs.allow-jit
  
  
  
  com.apple.security.cs.allow-dyld-environment-variables
  
  
  
  com.apple.security.cs.disable-library-validation
  
  
  
  com.apple.security.get-task-allow
  
  
  
  com.apple.security.files.user-selected.read-write
  
  
  
  com.apple.security.files.downloads.read-write
  

⚠️Apple Silicon (M1/M2/M3) 注意事项

如果你使用 Apple Silicon Mac 开发,打包的 x64 版本需要在 Intel Mac 上测试。 建议同时构建 x64arm64 两个版本,或使用 universal 二进制(体积较大)。

8.5 资源文件管理

应用中的静态资源(图标、字体、模板文件等)需要正确配置才能在打包后正常访问。

资源文件路径处理

javascript
const path = require('path');
const { app } = require('electron');

// 判断是否为打包后的应用
const isPackaged = app.isPackaged;

// 获取资源路径的辅助函数
function getResourcePath(relativePath) {
  if (isPackaged) {
    // 打包后:资源在 app.asar 或 app.getAppPath() 中
    return path.join(process.resourcesPath, relativePath);
  } else {
    // 开发环境:资源在项目根目录
    return path.join(__dirname, '..', relativePath);
  }
}

// 使用示例
const iconPath = getResourcePath('assets/icon.png');
const templatePath = getResourcePath('templates/report.html');

// 在 Vue 组件中访问静态资源
// 开发环境:直接引用 public 目录下的文件
// 生产环境:使用 app:// 协议或 file:// 协议

extraResources 配置

某些文件(如可执行程序、动态库)不能打包到 asar 中,需要放在 extraResources 中:

yaml
extraResources:
  # 整个目录
  - from: "assets/"
    to: "assets"
    filter:
      - "**/*"
  
  # 单个文件
  - from: "bin/ffmpeg"
    to: "bin/ffmpeg"
  
  # 根据平台选择不同文件
  - from: "bin/win/"
    to: "bin"
    filter:
      - "**/*"
  
  # 排除某些文件
  - from: "templates/"
    to: "templates"
    filter:
      - "**/*.html"
      - "**/*.css"
      - "!**/*.tmp"

8.6 打包命令与 CI/CD

配置好打包脚本后,可以通过命令行或 CI/CD 流水线自动构建和发布应用。

常用打包命令

bash
# 打包当前平台
npm run dist

# 仅打包 Windows
npm run dist:win

# 仅打包 macOS(需要在 Mac 上执行)
npm run dist:mac

# 仅打包 Linux
npm run dist:linux

# 生成不打包的安装目录(用于调试)
npm run pack

# 指定架构打包
npx electron-builder --win --x64
npx electron-builder --mac --arm64
npx electron-builder --win --ia32

GitHub Actions 自动打包

yaml
# .github/workflows/build.yml
name: Build and Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
    
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Build application
        run: npm run build
      
      - name: Build and release
        uses: samuelmeuli/action-electron-builder@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          release: ${{ startsWith(github.ref, 'refs/tags/v') }}
        env:
          # macOS 签名(如果需要)
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
          # Windows 签名(如果需要)
          WIN_CSC_LINK: ${{ secrets.WIN_CERTIFICATE }}
          WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CERT_PASSWORD }}

8.7 发布到 GitHub Releases

electron-builder 可以自动将打包结果上传到 GitHub Releases,配合自动更新功能实现应用分发。

yaml
# electron-builder.yml - 发布配置
publish:
  provider: github
  owner: your-username
  repo: your-repo-name
  releaseType: release  # 或 draft(草稿)
  # 私有仓库需要 token
  # token: ${env.GH_TOKEN}

# 或者在 package.json 中配置
"build": {
  "publish": {
    "provider": "github",
    "releaseType": "release"
  }
}
💡打包最佳实践
  • 版本号管理:使用语义化版本(semver),如 1.2.3
  • 构建前清理:确保每次构建都是干净的,删除旧的构建产物
  • 测试安装包:在干净的虚拟机中测试安装和卸载流程
  • 文件大小优化:排除不必要的依赖和文件,使用 asar 压缩
  • 多架构支持:同时提供 x64 和 arm64 版本(macOS)