Electron打包分发:签名、公证、自动更新和体积优化
Electron 应用写完了不算完——打包、签名、分发、自动更新,每一步都有坑。Windows 上没签名的安装包会被 SmartScreen 拦截,macOS 上没公证的应用直接打不开,安装包体积动辄 150MB+ 用户嫌大。这篇文章把打包到分发的完整流程走一遍。
打包工具选择
| 工具 | 特点 | 适合谁 |
|---|---|---|
| electron-builder | 功能最全,签名+更新+多格式一步到位 | 生产环境首选 |
| electron-forge | 官方推荐,集成开发+打包+发布流程 | 新项目开箱即用 |
| electron-packager | 只打包不安装包,功能简单 | 只需要可执行文件 |
大部分项目选 electron-builder 就对了。
electron-builder 配置
bashnpm install --save-dev electron-builder
在 package.json 里配置:
json{ "build": { "appId": "com.yourcompany.yourapp", "productName": "YourApp", "directories": { "output": "dist" }, "files": [ "build/**/*", "node_modules/**/*", "package.json" ], "win": { "target": [{ "target": "nsis", "arch": ["x64"] }], "icon": "build/icon.ico" }, "mac": { "target": [{ "target": "dmg", "arch": ["x64", "arm64"] }], "icon": "build/icon.icns", "category": "public.app-category.productivity", "hardenedRuntime": true, "gatekeeperAssess": false, "entitlements": "build/entitlements.mac.plist", "entitlementsInherit": "build/entitlements.mac.plist" }, "linux": { "target": ["AppImage", "deb"], "icon": "build/icon.png", "category": "Utility" } } }
打包命令:
bashnpx electron-builder --win # Windows npx electron-builder --mac # macOS npx electron-builder --linux # Linux npx electron-builder -mwl # 全平台(需要在对应系统上跑)
NSIS 安装程序(Windows)
NSIS 是 Windows 上最常用的安装包格式:
json{ "build": { "nsis": { "oneClick": false, "allowToChangeInstallationDirectory": true, "createDesktopShortcut": true, "createStartMenuShortcut": true, "shortcutName": "YourApp", "uninstallDisplayName": "YourApp", "license": "LICENSE.txt" } } }
oneClick: false 让用户选择安装目录,而不是一闪而过安装完。createDesktopShortcut 看似方便,但很多用户反感桌面图标——建议设为 alwaysCreate: false 让用户自己勾选。
代码签名
不签名的应用会被操作系统拦截:Windows 的 SmartScreen 弹蓝框,macOS 的 Gatekeeper 直接说"无法验证开发者"。
Windows 签名
需要购买代码签名证书(EV 或 Standard)。EV 证书签名后 SmartScreen 立即信任,Standard 证书需要积累信誉。
bash# 环境变量方式(CI/CD 推荐) export CSC_LINK=path/to/certificate.pfx export CSC_KEY_PASSWORD=your-password npx electron-builder --win
electron-builder 检测到 CSC_LINK 环境变量后自动签名,不用额外配置。
macOS 签名和公证
macOS 要求应用同时签名和公证(Notarization),否则用户打开时会弹"无法验证开发者"。
签名需要 Apple Developer 证书,公证需要 Apple ID:
bashexport CSC_LINK=path/to/developer-id.p12 export CSC_KEY_PASSWORD=your-password export APPLE_ID=your@email.com export APPLE_APP_SPECIFIC_PASSWORD=xxxx-xxxx-xxxx-xxxx export APPLE_TEAM_ID=XXXXXXXXXX npx electron-builder --mac
electron-builder 在 mac.hardenedRuntime: true 的情况下会自动签名并提交公证。公证过程需要 1-5 分钟,期间应用无法分发。
entitlements.mac.plist 文件(声明权限):
xml<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.cs.allow-jit</key> <true/> <key>com.apple.security.cs.allow-unsigned-executable-memory</key> <true/> <key>com.apple.security.cs.allow-dyld-environment-variables</key> <true/> </dict> </plist>
Electron 需要这三个权限:JIT(V8 引擎)、unsigned memory(渲染进程)、dyld variables(native 模块加载)。不声明的话签名后应用会崩溃。
自动更新
electron-updater 是 electron-builder 配套的自动更新方案,支持差分更新(只下载变化部分):
bashnpm install electron-updater
javascriptconst { autoUpdater } = require('electron-updater') const log = require('electron-log') autoUpdater.logger = log autoUpdater.autoDownload = false // 不自动下载,先提示用户 app.whenReady().then(() => { autoUpdater.checkForUpdates() autoUpdater.on('update-available', (info) => { // 通知用户有新版本 dialog.showMessageBox({ type: 'info', title: '发现新版本', message: `新版本 ${info.version} 可用,是否现在下载?`, buttons: ['下载', '稍后'] }).then(({ response }) => { if (response === 0) autoUpdater.downloadUpdate() }) }) autoUpdater.on('update-downloaded', () => { dialog.showMessageBox({ type: 'info', title: '更新就绪', message: '新版本已下载,重启应用以完成安装。', buttons: ['立即重启', '稍后'] }).then(({ response }) => { if (response === 0) autoUpdater.quitAndInstall() }) }) })
更新源配置在 package.json:
json{ "build": { "publish": { "provider": "github", "owner": "your-username", "repo": "your-repo" } } }
支持 GitHub Releases、S3、通用 HTTP 服务器。发布新版本时,electron-builder 自动把安装包上传到 GitHub Releases,autoUpdater 检查 latest.yml 判断是否有更新。
体积优化
Electron 应用默认 150MB+,因为包含了完整的 Chromium。可以压缩:
排除不需要的文件
json{ "build": { "files": [ "build/**/*", "!build/samples/**/*", "node_modules/**/*", "!node_modules/*/test/**/*", "!node_modules/*/docs/**/*", "!node_modules/*.md" ] } }
! 开头表示排除。test、docs、README 等文件打包后不需要。
asar 归档
asar 把源码打包成只读归档,减少文件数量和体积:
json{ "build": { "asar": true, "asarUnpack": [ "node_modules/native-module/**/*" // native 模块不能放进 asar ] } }
native 模块(better-sqlite3、keytar 等)必须 unpack,因为它们需要加载 .node 动态库,asar 里的文件不能直接 dlopen。
双架构 vs 通用二进制
macOS 支持 Universal 二进制(同时包含 x64 和 arm64),但体积翻倍。如果不需要 Rosetta 兼容,单独打 arm64 体积小一半:
json{ "build": { "mac": { "target": [{ "target": "dmg", "arch": ["arm64"] }] } } }
M1/M2/M3 用户占 macOS 大多数,只打 arm64 够用。需要兼容 Intel 的场景再打 Universal。
CI/CD 自动化
用 GitHub Actions 自动打包:
yamlname: Build on: push jobs: build: strategy: matrix: os: [windows-latest, macos-latest, ubuntu-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 20 } - run: npm ci - run: npx electron-builder --publish always env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} CSC_LINK: ${{ secrets.CSC_LINK }} CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
关键点:每个平台必须在对应 OS 上打包。Windows 安装包不能在 macOS 上交叉编译(签名工具不兼容)。macOS 公证也必须在 macOS 上跑。