☰
使用 Electron Forge 对 macOS 应用进行代码签名与公证(Code Signing Notarization)
2026/10/7 9:34:46 网站建设 项目流程
  • 开发工具
  • 桌面应用
  • 前端构建

【免费下载链接】forge

:electron: A complete tool for building and publishing Electron applications

项目地址:https://gitcode.com/gh_mirrors/fo/forge
点击查看免费下载

本指南基于 Electron Forge 仓库中的 docs/guides/code-signing/code-signing-macos.md 编写,源码佐证来自 packages/api/core/src/api/package.ts 与 packages/maker/pkg/src/MakerPKG.ts。

在 macOS 上,应用分发涉及两层安全技术:代码签名(Code Signing)与公证(Notarization)。代码签名用于证明应用出自你之手、分发前未被篡改;公证则是在代码签名的基础上,将应用提交至 Apple 服务器进行自动化恶意软件扫描的额外验证步骤。本指南面向使用 Electron Forge 打包并分发 macOS 应用的开发者,介绍如何安装证书、在packagerConfig中配置osxSign与osxNotarize,以及如何在forge.config.js中安全地读取凭证。读完本指南,你将能够在 Forge 的 Package 步骤中一次性完成签名与公证配置,并理解其底层调用链与可选参数。

macOS 分发安全体系概览

macOS 应用分发时面临两层安全技术:

  • 代码签名:对应用作者身份进行认证,并确保分发前未被篡改。
  • 公证:将应用提交至 Apple 服务器进行自动化恶意软件扫描,是额外的一道验证。

从 macOS 10.15(Catalina)开始,应用若要正常运行在用户机器上且不触发额外的系统安全检查,需要同时完成代码签名和公证。唯一的例外是 Mac App Store(MAS)应用:其提交流程本身包含类似的自动化检查,因此不需要公证。因此在packagerConfig中,MAS 与直接分发(Developer ID)场景的签名配置需求是有所区分的。

前置条件

安装 Xcode

Xcode 是 Apple 面向 macOS、iOS 等平台的集成开发环境。虽然 Electron 与 IDE 本身耦合不深,但 Xcode 对以下两个环节必不可少:

  1. 帮助你安装代码签名证书;
  2. 公证(notarization)所必需。

在 macOS 上完成签名与公证,Xcode(及其附带的命令行工具)是官方推荐的入口。

获取签名证书

macOS 应用的代码签名证书只能通过购买Apple Developer Program会员资格获得。签名 Electron 应用时,可能需要两个不同的证书:

证书用途
Developer ID Installer分发给Mac App Store的应用
Developer ID Application在Mac App Store 之外直接分发的应用

获得会员资格后,需要先将证书安装到本机。官方推荐通过 Xcode 加载证书。安装完成后,可以用以下 shell 命令在终端验证可用的代码签名证书:

security find-identity -p codesigning -v

如果输出中列出了你的证书(形如Developer ID Application: Your Name (TEAM1234567)),说明证书已正确安装。

配置 Forge:签名与公证发生在哪个环节

在 Electron Forge 中,macOS 应用的签名与公证发生在Package 步骤,由@electron/packager驱动。packagerConfig中的两个独立选项分别对应这两件事:

  • osxSign:控制代码签名;
  • osxNotarize:控制公证。

从源码看,这一流程发生在 packages/api/core/src/api/package.ts 中。Forge 会将forgeConfig.packagerConfig展开合并进传给@electron/packager的选项对象(第 417-435 行附近):

const packageOpts: PackagerOptions = { asar: false, overwrite: true, ignore: [/^\/out\//g], quiet: true, ...forgeConfig.packagerConfig, // ... };

也就是说,packagerConfig中与@electron/packager兼容的字段(包括osxSign、osxNotarize)都会被透传给底层打包库。而packagerConfig的默认值在 packages/api/core/src/util/forge-config.ts 中定义为空对象{}(第 198 行),这正解释了"osxSign对象必须存在(即使为空)"的原因:配置合并时,只有显式声明的字段才会被带上。

此外,.pkg安装包的制作也复用了同一套osxNotarize配置:在 packages/maker/pkg/src/MakerPKG.ts 中,当config.identity存在且forgeConfig.packagerConfig.osxNotarize存在时,会对生成的.pkg文件调用notarize(第 48-53 行):

if (this.config.identity && forgeConfig.packagerConfig.osxNotarize) { await notarize({ ...forgeConfig.packagerConfig.osxNotarize, appPath: outPath, }); }

该行为的测试用例位于 packages/maker/pkg/spec/MakerPKG.spec.ts,分别覆盖"配置了 identity 与 osxNotarize 时执行 notarize"、"缺少 identity 时不 notarize"、"缺少 osxNotarize 时不 notarize"三种场景。

osxSign 选项

Forge 底层使用@electron/osx-sign工具对 macOS 应用进行签名。要启用代码签名,只需保证packagerConfig.osxSign存在:

module.exports = { packagerConfig: { osxSign: {} // 对象必须存在,即使为空 } };

osxSign配置自带一组开箱即用的默认值,绝大多数场景下建议从一个空配置对象开始。完整的选项列表可查阅 Forge API 文档中的OsxSignOptions类型;更详细的选项说明可参考@electron/osx-sign的文档。

自定义 entitlements

修改默认osxSign配置最常见的诉求是自定义entitlements。在 macOS 中,entitlements 是授予应用的权限(例如访问摄像头、麦克风或 USB 设备),它们存储于应用可执行文件的代码签名中。

默认情况下,@electron/osx-sign自带一组适用于 MAS 或直接分发目标的 entitlements 文件。如果需要按文件粒度定制,可以使用optionsForFile回调:它接收打包后应用中的每个文件路径,并返回该文件对应的签名选项:

module.exports = { // ... packagerConfig: { // ... osxSign: { optionsForFile: (filePath) => { // 这里保持简单:对每个文件都返回同一个 entitlements.plist。 // 你也可以利用这个回调,把不同的 entitlements 集合 // 映射到打包应用中的不同文件。 return { entitlements: 'path/to/entitlements.plist' }; } } } // ... };

如需进一步了解 entitlements 机制,可参考 Apple 开发者文档中的Entitlements与Hardened Runtime页面。

osxNotarize 选项

Forge 底层使用@electron/notarize工具完成公证。notarytool命令支持三种认证方式,下面逐一说明。注意:为了把环境变量加载进 Forge 配置,你需要使用forge.config.js这类 JS 配置文件(而不是纯 JSON 的package.json内联配置)。

务必保护你的认证信息绝不要把认证信息以明文形式写死在配置里。下面的示例都把凭证存放在环境变量中,通过 Node.js 的process.env对象读取。

方式一:使用 App-Specific Password(应用专用密码)

先从 Apple 生成一个应用专用密码来向notarytool提供凭证。注意:如果更改了 Apple ID 密码,此密码需要重新生成。

使用该策略时,osxNotarize有以下三个字段(其中前两个为必填):

字段类型描述
appleIdstring与你的 Apple Developer 账号关联的 Apple ID
appleIdPasswordstring应用专用密码(不是Apple ID 登录密码!)
teamIdstring你要在其名下公证的 Apple Team ID。可以在https://developer.apple.com/account/#/membership找到你所属团队的 Team ID
module.exports = { // ... packagerConfig: { // ... osxNotarize: { appleId: process.env.APPLE_ID, appleIdPassword: process.env.APPLE_PASSWORD, teamId: process.env.APPLE_TEAM_ID } } // ... };

提醒:尽管字段名叫appleIdPassword,它并不是你的 Apple ID 账号密码。

方式二:使用 App Store Connect API Key

在 App Store Connect 的"Team Keys"标签页生成 API Key 来认证notarytool。生成的 API Key 形如AuthKey_ABCD123456.p8,且只能下载一次。

使用该策略时,osxNotarize有以下三个必填字段:

字段类型描述
appleApiKeystringAPI Key 文件的文件系统路径
appleApiKeyIdstring10 位字母数字 ID。以AuthKey_ABCD123456.p8为例,该值为ABCD123456
appleApiIssuerstring标识 API Key 签发者的 UUID,可在生成 API Key 的"Keys"标签页找到
module.exports = { // ... packagerConfig: { // ... osxNotarize: { appleApiKey: process.env.APPLE_API_KEY, appleApiKeyId: process.env.APPLE_API_KEY_ID, appleApiIssuer: process.env.APPLE_API_ISSUER } } // ... };
方式三:使用 Keychain(钥匙串)

除了通过环境变量把凭证传给 Forge 配置,你也可以使用 macOS 的钥匙串(keychain)保存上述任一方式的凭证。在终端直接执行notarytool store-credentials即可;使用说明可查阅notarytool的 man page:

man notarytool

使用该策略时,osxNotarize有以下字段:

字段类型描述
keychainProfilestring存放公证凭证的钥匙串配置文件名称
keychain(可选)string存放该凭证配置的钥匙串名称(或路径)

注意:如果你使用notarytool store-credentials保存凭证,keychain参数可以被自动检测到。

module.exports = { // ... packagerConfig: { // ... osxNotarize: { keychainProfile: 'my-keychain-profile' } } // ... };

完整示例配置

下面是一份同时配置osxSign与osxNotarize的最小 Forge 配置:

module.exports = { packagerConfig: { osxSign: {}, osxNotarize: { appleId: process.env.APPLE_ID, appleIdPassword: process.env.APPLE_PASSWORD, teamId: process.env.APPLE_TEAM_ID } } };

配套参考

  • 本指南对应的平台索引页:docs/guides/code-signing/index.md
  • Windows 平台的签名指南:docs/guides/code-signing/code-signing-windows.mdx
  • 若你使用.pkg制作器,签名相关的额外配置(如identity、identityValidation)可参考 packages/maker/pkg/src/Config.ts 及其文档 docs/config/makers/pkg.mdx
  • 开发工具
  • 桌面应用
  • 前端构建

【免费下载链接】forge

:electron: A complete tool for building and publishing Electron applications

项目地址:https://gitcode.com/gh_mirrors/fo/forge
点击查看免费下载

相关推荐

上一篇:rsuite Animation.Transition 自定义动画完全指南:从状态机原理到 Zoom / Flip / Rotate / Bounce 实战
下一篇:如何快速掌握Firecrawl:智能网页数据提取的完整实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询