Electron 在 macOS 10.14.5及以上申请公证(Notarization)
不知道大家最近分发网上下载的 App 时有没有遇到这个安全报错。

打不开“XXX.app”,因为 Apple 无法检查其是否包含恶意软件。
此软件需要更新。请联系开发者来了解更多信息。
事实上从macOS 10.14.5开始,所有开发人员签名的 App 都需要进行公证(Notarization),否则将触发苹果的Gatekeeper阻止用户安装 App。这意味着我们除了对 App 进行签名以外,还需要对其进行公证。不然你就会看到上面的错误消息。
所以这篇文章将和大家讲下如何在 macOS 10.14.5 以上公证 Electron App。
以下是 Electron 的公证流程概述:
- 使用
hardened runtime
构建 App - 使用有效的开发者ID进行签名
- 使用
electron-notarize
公证 App - 不要对 dmg 签名
这里我用 electronic-builder: ^20.43.0
为例进行说明。
1. 使用 hardened runtime 构建App
在添加公证时,苹果其实偷偷加入了一项要求,即App的 runtime 必须是 hardened runtime
(默认情况下会减少应用程序的权限)。
将 App runtime 设置成 hardened runtime
需要做两件事:
- 在
electron-builder
的mac
配置选项中设置"hardenedRuntime": true
; - 设定正确的权限。运行
hardened runtime
时,至少设置一个非常重要的权限:“allow-unsigned-executable-memory”
。当然你也可以在此处指定更多权限,但这是 Electron App 所需的唯一权限。此权限应包含在构建文件夹中的 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-unsigned-executable-memory</key>
<true/>
</dict>
</plist>
在 electron-builder
的 mac
配置选项中,需要将 entitlements
和 entitlementsInherits
的值同时设置为这个文件的路径。
PS:通过
entitlementsInherits
这个配置可以授予Electron在内部访问权限文件时相同的权限。
"mac": {
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist"
},
2. 使用有效的开发者ID进行签名
只有当你的 Mac上安装了有效的开发者ID 时,才能对App进行公证。electron-bulder
将自动从钥匙串中获取一个有效 ID 进行签名。这就需要你有一个Apple的开发者账号。关于这一点,我就不再赘述了。
但是,electron-builder
使用的签名工具(electronic -osx-sign)会进行完整性检查以验证签名是否成功。在MacOS 10.14.5之前,这个完整性检查将返回True
,但在MacOS 10.14.5 中,它会返回false
。因为虽然签名进行完毕了,但应用程序还没有公证信息,所以会返回 false
。
所以我们需要禁用这种完整性检查。你可以通过在 electron-builder
的 mac
配置中设置"gatekeeperAssess":false
来实现。
最后,我们来看下 mac
参数的配置情况:
"mac": {
"hardenedRuntime" : true,
"gatekeeperAssess": false,
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist"
},
3. 使用electron-notarize
公证App
接下来则是关于公证的部分。我们使用的工具叫 electron-notarize
。因为只需要在开发阶段使用,因此记得安装到 devDependency。
这个工具可以完成公证的所有工作:将App打包并上传到Apple的服务器,等待公证成功,然后给App加入公证信息。这些流程是异步发送的,但是即便如此,构建过程还是会增多不少时间。
App应该在签名之后,打包成DMG之前进行公证。electron-builder
有一个afterSign
的钩子,通过执行对应的 js 文件。这个配置选项在“build”配置中。
"build": {
"afterSign": "scripts/notarize.js"
}
afterSign.js
代码如下:
require('dotenv').config();
const { notarize } = require('electron-notarize');
exports.default = async function notarizing(context) {
const { electronPlatformName, appOutDir } = context;
if (electronPlatformName !== 'darwin') {
return;
}
const appName = context.packager.appInfo.productFilename;
return await notarize({
appBundleId: 'com.yourcompany.yourAppId',
appPath: `${appOutDir}/${appName}.app`,
appleId: process.env.APPLEID,
appleIdPassword: process.env.APPLEIDPASS,
});
};
我们只需要签署MacOS,所以如果我们不在darwin(macOS的内部名称)上,我们返回并且不运行公证代码。
我使用 dotenv
从.env
文件中轻松获取环境变量,因此我不必将真实用户凭据添加到我的脚本中。如果您使用git,请务必将.env
添加到.gitignore
文件中。为了更好的安全性,请考虑使用此处概述的MacOS钥匙串:使用appleIdPassword时的安全性。
关于用户凭证,这是你的Apple ID,但是你需要生成一个特定于应用程序的密码(所以不要使用常规密码哦)你可以在appleid.apple.com上创建一个。
4. 不要对dmg签名
在版本20.43.0之前,electronic-builder
还签署了您的DMG安装程序。这实际上不是一个问题,但是在新的公证规则下,任何签署的东西都需要公证。
但是,如果对DMG安装包签名并公证,它实际上会触发之前看到的错误。这可能是 Apple 审核逻辑中的一个错误。既然这个错误存在,我们必须要使用未经过公证的DMG文件。Apple的Gatekeeper可以检测到DMG中的经过公证的.app
文件,并且可以让用户正常打开App。
从electronic-builder 20.43.0开始,默认情况下DMG是无签名的。您可以通过在“dmg”
配置中添加“sign”:false
来显式地处理这种行为:
"dmg": {
"sign": false
},
最后,回顾一下签名的配置文件吧~
// electron-builder.json
"mac": {
"hardenedRuntime" : true,
"gatekeeperAssess": false,
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist"
},
"dmg": {
"sign": false
}
// package.json
"build": {
"afterSign": "scripts/notarize.js"
}