Mac App Store 提交指南
本指南提供以下信息:
- 如何在 macOS 上签署 Electron 应用程序;
- 如何将 Electron 应用程序提交到 Mac App Store (MAS);
- MAS 构建的限制。
要求
要签署 Electron 应用程序,必须首先安装以下工具:
- Xcode 11 或更高版本。
- @electron/osx-sign npm 模块。
您还必须注册一个 Apple Developer 帐户并加入 Apple Developer Program。
签署 Electron 应用程序
Electron 应用程序可以通过 Mac App Store 或在外部进行分发。每种方式都需要不同的签名和测试方法。本指南侧重于通过 Mac App Store 进行分发。
以下步骤描述了如何从 Apple 获取证书、如何签署 Electron 应用程序以及如何测试它们。
获取证书
获取签名证书的最简单方法是使用 Xcode
- 打开 Xcode 并打开“帐户”偏好设置;
- 使用您的 Apple 帐户登录;
- 选择一个团队,然后单击“管理证书”;
- 在签名证书表的左下角,单击“添加”按钮 (+),并添加以下证书:
- “Apple Development”(Apple 开发)
- “Apple Distribution”(Apple 分发)
“Apple Development”证书用于为在 Apple Developer 网站上注册的机器上的开发和测试签名应用程序。注册方法将在 准备配置文件 中进行描述。
使用“Apple Development”证书签名的应用程序无法提交到 Mac App Store。为此,必须使用“Apple Distribution”证书对应用程序进行签名。但请注意,使用“Apple Distribution”证书签名的应用程序无法直接运行,必须由 Apple 重新签名才能运行,这只能在从 Mac App Store 下载后才能实现。
其他证书
您可能会注意到还有其他类型的证书。
“Developer ID Application”证书用于在 Mac App Store 之外分发应用程序之前对其进行签名。
“Developer ID Installer”和“Mac Installer Distribution”证书用于对 Mac 安装程序包而不是应用程序本身进行签名。大多数 Electron 应用程序不使用 Mac 安装程序包,因此通常不需要它们。
证书类型的完整列表可以在此处找到。
使用“Apple Development”和“Apple Distribution”证书签名的应用程序只能在 App Sandbox 下运行,因此它们必须使用 Electron 的 MAS 构建。但是,“Developer ID Application”证书没有此限制,因此使用它签名的应用程序可以使用 Electron 的标准构建或 MAS 构建。
旧版证书名称
Apple 在过去几年中一直在更改证书的名称,您在阅读旧文档时可能会遇到它们,并且一些实用程序仍然使用旧名称之一。
- “Apple Distribution”证书也称为“3rd Party Mac Developer Application”和“Mac App Distribution”。
- “Apple Development”证书也称为“Mac Developer”和“Development”。
准备配置文件
如果您想在将应用程序提交到 Mac App Store 之前在本地计算机上测试您的应用程序,则必须使用“Apple Development”证书对应用程序进行签名,并将配置文件嵌入到应用程序捆绑包中。
要创建配置文件,您可以按照以下步骤操作:
- 打开 Apple Developer 网站上的“证书、标识符和配置文件”页面。
- 在“标识符”页面中为您的应用程序添加新的 App ID。
- 在“设备”页面中注册您的本地计算机。您可以在“系统信息”应用程序的“硬件”页面中找到您计算机的“设备 ID”。
- 在“配置文件”页面中注册一个新的配置文件,并将其下载到
/path/to/yourapp.provisionprofile
。
启用 Apple 的应用沙盒
提交到 Mac App Store 的应用程序必须在 Apple 的 App Sandbox 下运行,并且只有 Electron 的 MAS 构建才能在 App Sandbox 中运行。当在 App Sandbox 下运行时,Electron 的标准 darwin 构建将无法启动。
当使用 @electron/osx-sign
签署应用程序时,它会自动将必要的授权添加到您应用程序的授权中。
没有 electron-osx-sign
的额外步骤
如果您在不使用 @electron/osx-sign
的情况下签署应用程序,则必须确保应用程序捆绑包的授权至少具有以下键:
<?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.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>TEAM_ID.your.bundle.id</string>
</array>
</dict>
</plist>
TEAM_ID
应替换为您的 Apple Developer 帐户的团队 ID,your.bundle.id
应替换为应用程序的 App ID。
以下授权必须添加到应用程序捆绑包中的二进制文件和帮助程序中:
<?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.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
并且应用程序捆绑包的 Info.plist
必须包含 ElectronTeamID
键,该键的值为您的 Apple Developer 帐户的团队 ID:
<plist version="1.0">
<dict>
...
<key>ElectronTeamID</key>
<string>TEAM_ID</string>
</dict>
</plist>
当使用 @electron/osx-sign
时,ElectronTeamID
键将通过从证书的名称中提取团队 ID 来自动添加。如果 @electron/osx-sign
找不到正确的团队 ID,您可能需要手动添加此键。
签署用于开发的应用程序
要签署可以在您的开发机器上运行的应用程序,您必须使用“Apple Development”证书对其进行签名,并将配置文件传递给 @electron/osx-sign
。
const { signAsync } = require('@electron/osx-sign')
signAsync({
app: '/path/to/your.app',
identity: 'Apple Development',
provisioningProfile: '/path/to/your.provisionprofile'
})
如果您在不使用 @electron/osx-sign
的情况下进行签名,则必须将配置文件放置到 YourApp.app/Contents/embedded.provisionprofile
。
签名的应用程序只能在配置文件注册的机器上运行,这是在提交到 Mac App Store 之前测试签名的应用程序的唯一方法。
签署用于提交到 Mac App Store 的应用程序
要签署将提交到 Mac App Store 的应用程序,您必须使用“Apple Distribution”证书对其进行签名。请注意,使用此证书签名的应用程序将无法在任何地方运行,除非是从 Mac App Store 下载的。
const { signAsync } = require('@electron/osx-sign')
signAsync({
app: 'path/to/your.app',
identity: 'Apple Distribution'
})
将应用程序提交到 Mac App Store
使用“Apple Distribution”证书签署应用程序后,您可以继续将其提交到 Mac App Store。
但是,本指南不保证您的应用程序将获得 Apple 的批准;您仍然需要阅读 Apple 的 提交您的应用程序 指南,了解如何满足 Mac App Store 的要求。
上传
Apple Transporter 应用于将已签名的应用程序上传到 App Store Connect 进行处理,确保您在上传之前创建了记录。
如果您看到诸如使用私有 API 之类的错误,则应检查该应用程序是否正在使用 Electron 的 MAS 构建。
提交以供审核
上传后,您应该提交您的应用程序以供审核。
MAS 构建的限制
为了满足应用沙箱的所有要求,MAS 构建中禁用了以下模块
crashReporter
autoUpdater
并且更改了以下行为
- 视频捕获可能在某些机器上无法工作。
- 某些辅助功能可能无法工作。
- 应用将无法感知 DNS 更改。
此外,由于使用了应用沙箱,应用可以访问的资源受到严格限制;您可以阅读应用沙箱以获取更多信息。
额外授权
每个在应用沙箱下运行的应用都将在有限的权限集下运行,这限制了恶意代码可能造成的损害。 根据您的应用使用的 Electron API,您可能需要在应用的授权文件中添加额外的授权。 否则,应用沙箱可能会阻止您使用它们。
授权使用类似属性列表(.plist
)或 XML 格式的文件指定。 您必须为应用捆绑包本身提供一个授权文件,以及一个子授权文件,该文件基本上描述了为所有其他封闭的可执行文件(如二进制文件,框架(.framework
)和动态链接库(.dylib
))指定的属性继承。
应用沙箱文档中提供了完整的授权列表,但以下是您的 MAS 应用可能需要的一些授权。
使用 @electron/osx-sign
,您可以按如下方式为每个文件设置自定义授权
const { signAsync } = require('@electron/osx-sign')
function getEntitlementsForFile (filePath) {
if (filePath.startsWith('my-path-1')) {
return './my-path-1.plist'
} else {
return './alternate.plist'
}
}
signAsync({
optionsForFile: (filePath) => ({
// Ensure you return the right entitlements path here based on the file being signed.
entitlements: getEntitlementsForFile(filePath)
})
})
网络访问
启用出站网络连接以允许您的应用连接到服务器
<key>com.apple.security.network.client</key>
<true/>
启用入站网络连接以允许您的应用打开网络监听套接字
<key>com.apple.security.network.server</key>
<true/>
有关更多详细信息,请参阅启用网络访问文档。
dialog.showOpenDialog
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
有关更多详细信息,请参阅启用用户选择的文件访问文档。
dialog.showSaveDialog
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
有关更多详细信息,请参阅启用用户选择的文件访问文档。
Electron 使用的加密算法
根据您发布应用的国家/地区,您可能需要提供有关软件中使用的加密算法的信息。 有关更多信息,请参阅加密出口合规性文档。
Electron 使用以下加密算法
- AES - NIST SP 800-38A, NIST SP 800-38D, RFC 3394
- HMAC - FIPS 198-1
- ECDSA - ANS X9.62–2005
- ECDH - ANS X9.63–2001
- HKDF - NIST SP 800-56C
- PBKDF2 - RFC 2898
- RSA - RFC 3447
- SHA - FIPS 180-4
- Blowfish - https://www.schneier.com/cryptography/blowfish/
- CAST - RFC 2144, RFC 2612
- DES - FIPS 46-3
- DH - RFC 2631
- DSA - ANSI X9.30
- EC - SEC 1
- IDEA - X. Lai 的“关于分组密码的设计和安全性”一书
- MD2 - RFC 1319
- MD4 - RFC 6150
- MD5 - RFC 1321
- MDC2 - ISO/IEC 10118-2
- RC2 - RFC 2268
- RC4 - RFC 4345
- RC5 - https://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf
- RIPEMD - ISO/IEC 10118-3