macOS 证书配置(不上架 App Store 的情况)
概述
macOS 应用打包后如果未签名,用户安装时会收到"未知开发者"的安全警告。本节介绍如何通过 Apple Developer 账号获取 Developer ID 证书,对应用进行代码签名,使应用可以直接分发(不上架 App Store)。
证书类型对比
| 证书类型 | 用途 | 分发方式 | 是否需要公证 |
|---|---|---|---|
| Development | 开发调试 | 仅本地测试 | 否 |
| Developer ID Application | 直接分发(推荐) | 网站/第三方平台 | 是 |
| Mac App Store | App Store 分发 | Mac App Store | 由 Apple 审核 |
核心要点:不上架 App Store 的应用应申请 Developer ID Application 证书,签名后仍需经过 Apple 公证(Notarization)。
配置流程
1. 注册 Apple Developer 账号
- 访问 developer.apple.com
- 个人开发者年费 $99/年
- 企业团队账号适合多人协作(按需选择)
2. 通过 Xcode 配置证书
打开 Xcode → Settings (Preferences)
→ Accounts → 点击 "+" 添加 Apple ID
→ 登录后选择团队
→ Manage Certificates
→ 点击 "+" → 选择 "Developer ID Application"
text
3. 验证证书安装
# 列出系统中已安装的签名证书
security find-identity -v -p codesigning
# 输出示例:
# 1) ABC123... "Developer ID Application: Your Name (TEAM_ID)"
bash
4. 在 electron-builder 中配置签名
// electron-builder.config.ts
import type { Configuration } from 'electron-builder'
const config: Configuration = {
appId: 'com.toimc.tools',
mac: {
target: ['dmg'],
// 签名证书名称(与 Keychain 中的显示名称一致)
identity: 'Developer ID Application: Your Name (TEAM_ID)',
hardenedRuntime: true,
gatekeeperAssess: false,
entitlements: 'build/entitlements.mac.plist',
entitlementsInherit: 'build/entitlements.mac.inherit.plist'
}
}
export default config
typescript
5. 创建 Entitlements 文件
<!-- build/entitlements.mac.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.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
xml
6. 公证(Notarization)
签名后必须提交 Apple 公证,否则用户仍会看到安全警告。
// electron-builder.config.ts 中添加 afterSign 钩子
import { notarize } from '@electron/notarize'
const config: Configuration = {
// ...
afterSign: async (context) => {
if (context.electronPlatformName === 'darwin') {
await notarize({
appPath: context.appOutDir,
appleId: process.env.APPLE_ID,
appleIdPassword: process.env.APPLE_APP_PASSWORD,
teamId: process.env.APPLE_TEAM_ID
})
}
}
}
typescript
7. 环境变量配置
# .env(不提交到版本控制)
APPLE_ID=your-apple-id@email.com
APPLE_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx # App 专用密码
APPLE_TEAM_ID=YOUR_TEAM_ID
bash
生成 App 专用密码:appleid.apple.com → 登录 → App 专用密码 → 生成。
macOS 与 Windows 签名对比
| 维度 | macOS | Windows |
|---|---|---|
| 证书费用 | $99/年(含在开发者账号中) | $200-500/年(独立购买) |
| 签名工具 | Xcode / codesign | signtool |
| 公证要求 | 是(必须) | 否 |
| 无签名后果 | "未知开发者"警告 + 无法打开 | SmartScreen 蓝色警告 |
| 证书类型 | Developer ID Application | EV Code Signing / OV Code Signing |
构建与签名命令
# 构建 + 签名 + 公证(自动)
APPLE_ID=xxx APPLE_APP_PASSWORD=xxx APPLE_TEAM_ID=xxx \
npx electron-builder --mac
# 仅签名不公证(调试用)
CSC_NAME="Developer ID Application: Your Name (TEAM_ID)" \
npx electron-builder --mac --config.mac.identity="Developer ID Application: Your Name"
bash
实践要点
- 不上架 App Store 的应用使用 Developer ID Application 证书,而非 Mac App Store 证书
- 签名后仍需提交 Apple 公证(Notarization),否则 macOS 10.15+ 会阻止运行
hardenedRuntime: true是公证的前提条件- Entitlements 文件声明应用所需的权限(如 JIT、动态库加载等),根据实际需求配置
- Apple ID 和 App 专用密码通过环境变量传递,不要硬编码在配置文件中
- 企业团队建议注册企业账号,便于多人管理证书和描述文件
↑