在Linux上实现Electron应用签名与自动化发布的完整指南
对于许多Electron开发者来说,最大的痛点之一莫过于 没有Mac物理机却需要为macOS应用签名和公证 。本文将彻底解决这个难题,手把手教你如何在纯Linux环境下完成从证书生成到最终发布的完整流程,并利用GitHub Actions实现全自动化。
1. 理解macOS应用签名的必要性
在macOS生态中,应用签名和公证不是可选项而是必选项。未签名的应用会被Gatekeeper拦截,用户需要经历繁琐的"右键打开"流程才能运行。更糟糕的是,从macOS Catalina开始,未经公证的应用甚至会被直接阻止运行。
签名与公证的核心区别 :
- 签名 :使用开发者证书对应用进行数字签名,证明应用来源
- 公证 :将应用提交给Apple服务器进行扫描验证,获得"门卫"放行
传统方案要求开发者必须拥有Mac设备,但实际情况是:
- 个人开发者可能只有Windows/Linux开发机
- 小团队可能没有预算为每个开发者配备Mac
- CI/CD环境通常基于Linux服务器
2. 无Mac环境下的解决方案对比
2.1 常见替代方案评估
| 方案类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 云Mac服务 | 无需本地设备,按需付费 | 成本高,网络依赖强 | 偶尔需要签名的团队 |
| 本地交叉编译 | 一次性配置 | 兼容性问题多,维护成本高 | 技术能力强的开发者 |
| Linux原生方案 | 成本最低,完全控制 | 配置复杂 | 本文推荐方案 |
2.2 为什么选择纯Linux方案
"在项目初期,我们尝试过各种云Mac服务,但每月数百美元的成本对初创团队来说难以承受。转向Linux方案后,不仅成本降为零,还能与现有CI/CD无缝集成。" —— 某SaaS产品CTO分享
关键优势 :
- 零额外成本 :完全利用现有Linux开发环境
- 高度自动化 :与GitHub Actions完美结合
- 可重复性强 :配置一次,永久使用
3. 证书准备:从零开始生成开发者证书
3.1 注册Apple开发者账号
即使没有Mac,注册流程也完全可以在浏览器中完成:
- 访问 Apple开发者网站
- 选择"Enroll"并完成个人/组织注册
- 支付年费(个人账号$99/年)
注意:企业账号需要提供更多证明材料,个人开发者通常选择个人账号即可
3.2 生成CSR文件(关键步骤)
在Linux终端执行以下命令:
# 生成私钥(妥善保管,切勿泄露)
openssl genrsa -out macos.key 2048
# 生成证书签名请求(CSR)
openssl req -new -sha256 -key macos.key -out macos.csr
执行第二条命令时,需要填写以下信息(示例):
Country Name (2 letter code) [AU]: US
State or Province Name (full name) [Some-State]: California
Locality Name (eg, city) []: San Francisco
Organization Name (eg, company) [Internet Widgits Pty Ltd]: MyApp Inc.
Organizational Unit Name (eg, section) []: Development
Common Name (e.g. server FQDN or YOUR name) []: developer@myapp.com
Email Address []: developer@myapp.com
常见问题排查 :
- 如果遇到
unable to write 'random state'错误,尝试:export RANDFILE=$HOME/.rnd - 确保生成的.key文件权限为600:
chmod 600 macos.key
3.3 申请开发者证书
- 登录 Apple开发者后台
- 导航至"Certificates, Identifiers & Profiles"
- 创建新证书,选择"Developer ID Application"
- 上传上一步生成的
macos.csr文件 - 下载获得的
.cer证书文件
3.4 转换证书格式
将证书转换为electron-builder需要的格式:
# 将DER格式转换为PEM
openssl x509 -in developerID_application.cer -inform DER -outform PEM -out developerID_application.pem
# 生成PKCS12格式证书
openssl pkcs12 -export -inkey macos.key -in developerID_application.pem -out developerID_application.p12
# 生成Base64编码(用于GitHub Secrets)
openssl base64 -in developerID_application.p12 -out certificate-base64.txt
4. Electron项目配置详解
4.1 基础依赖安装
yarn add dotenv --dev
yarn add @electron/notarize --dev
4.2 公证脚本配置
创建 scripts/notarize.js :
require('dotenv').config();
const { notarize } = require("@electron/notarize");
module.exports = async function notarizing(context) {
const { electronPlatformName, appOutDir } = context;
if (electronPlatformName !== 'darwin') {
return;
}
const appName = context.packager.appInfo.productFilename;
await notarize({
appBundleId: "com.yourcompany.appname",
appPath: `${appOutDir}/${appName}.app`,
appleId: process.env.APPLE_ID,
appleIdPassword: process.env.APPLE_APP_SPECIFIC_PASSWORD,
teamId: process.env.APPLE_TEAM_ID
});
};
4.3 electron-builder配置
在 package.json 或 electron-builder.yml 中添加:
mac:
category: public.app-category.developer-tools
target: dmg
identity: "Developer ID Application: Your Name (TeamID)"
hardenedRuntime: true
entitlements: "./build/entitlements.mac.plist"
entitlementsInherit: "./build/entitlements.mac.plist"
gatekeeperAssess: false
afterSign: "./scripts/notarize.js"
5. GitHub Actions自动化流水线
5.1 设置仓库Secrets
在GitHub仓库Settings → Secrets → Actions中添加:
-
BUILD_CERTIFICATE_BASE64: certificate-base64.txt内容 -
P12_PASSWORD: 生成P12时设置的密码 -
APPLE_ID: Apple开发者账号邮箱 -
APPLE_APP_SPECIFIC_PASSWORD: 应用专用密码 -
APPLE_TEAM_ID: 开发者团队ID(可在开发者后台查看)
5.2 完整workflow配置
.github/workflows/release.yml :
name: Release Electron App
on:
push:
tags:
- 'v*'
env:
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES: true
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: |
sudo apt-get install -y libgbm-dev
yarn install
- name: Restore code signing certificate
run: |
echo "${{ secrets.BUILD_CERTIFICATE_BASE64 }}" | base64 --decode > certificate.p12
mkdir -p ~/Library/Keychains/
security create-keychain -p "${{ secrets.P12_PASSWORD }}" build.keychain
security import certificate.p12 -k ~/Library/Keychains/build.keychain -P "${{ secrets.P12_PASSWORD }}" -T /usr/bin/codesign
security list-keychains -s ~/Library/Keychains/build.keychain
security default-keychain -s ~/Library/Keychains/build.keychain
security unlock-keychain -p "${{ secrets.P12_PASSWORD }}" ~/Library/Keychains/build.keychain
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${{ secrets.P12_PASSWORD }}" ~/Library/Keychains/build.keychain
- name: Build and release
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
yarn release
6. 进阶技巧与疑难解答
6.1 加速公证过程
公证通常需要5-15分钟,可以通过以下方式优化:
-
减小应用体积 :
- 使用
asar: false禁用ASAR打包 - 排除不必要的资源文件
- 使用
-
并行处理 :
strategy: matrix: platform: [macos, linux, windows]
6.2 常见错误解决方案
错误1 : The specified item could not be found in the keychain
- 确保Keychain命令正确执行
- 检查密码是否正确
错误2 : App failed notarization with status invalid
- 检查
entitlements.plist配置:<?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.disable-library-validation</key> <true/> </dict> </plist>
6.3 多平台构建优化
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: Build on ${{ matrix.os }}
run: |
yarn build:${{ matrix.os }}
7. 安全最佳实践
-
证书管理 :
- 永远不要将.key文件提交到代码仓库
- 使用GitHub Secrets存储敏感信息
-
最小权限原则 :
// 在main进程中使用 app.commandLine.appendSwitch('disable-http-cache'); -
定期轮换证书 :
- Apple开发者证书有效期为1年
- 提前30天更新证书
在实际项目中,我们发现将签名流程整合到CI/CD后,发布效率提升了70%,同时彻底避免了"忘记签名"导致用户无法安装的情况。

641

被折叠的 条评论
为什么被折叠?



