Presenton Mac App Store 打包实操:证书、Profile 到 MAS 构建脚本全打通
【免费下载链接】presentonOpen-Source AI Presentation Generator and API (Gamma, Canva, Beautiful AI, Decktopus, Presentations AI Alternative)项目地址: https://gitcode.com/GitHub_Trending/pr/presenton
把 Presenton 的 Electron 客户端推进 Mac App Store 审核,最容易翻车的不是前端或后端代码,而是签名链:一个带-beta后缀的版本号、一个还躺在仓库里的占位 profile、一次钥匙串私钥授权弹窗——任何一环没接好,electron-builder都会在半路停下来报错。这篇按"Apple 侧一次性准备 → 沙盒权限 → 构建跑通 → 产物与自测"的顺序,带你把 Presenton Mac App Store 打包从证书申请做到.pkg上传,涉及的脚本、环境变量、报错对照表都落在仓库真实文件里。
三种打包目标,先认对门牌
Presenton 在 macOS 上把打包拆成三种目标,全部由环境变量PRESENTON_MAC_TARGET驱动,你在 npm 脚本里不用手动设它。选错目标,产物就装不上对应的分发渠道:
| 目标值 | 分发场景 | 对应 npm 脚本 |
|---|---|---|
dmg | 绕开 App Store 的直接下载 | npm run build:all:mac:signed |
mas-dev | 已注册 Mac 上的沙盒内测 | npm run build:all:mas-dev |
mas | 提交 Mac App Store 审核 | npm run build:all:mas |
所有打包逻辑集中在 electron/build.js 里。文件开头有两个常量值得先记住:APP_ID是com.presenton.presenton,即应用标识(Bundle ID);TEAM_ID是S6W5C54KL6,会写进mac.extendInfo.ElectronTeamID字段。这两个值是后面证书与 Profile 配置的锚点,换成你自己的团队就得同步改它们。
一次性搞定 Apple 的四件套
签名链的原料分四份,前两份是证书,第三份是 App ID,第四份是两份 profile。开发链路只用到前三份里的"开发证书",提交链路则要把分发那一套备齐。
开发用:一张 Apple Development 证书
在 Xcode →Settings→Accounts→ 你的团队 →Manage Certificates→+→Apple Development生成。它只服务于mas-dev目标和本地沙盒测试。
分发用:两张证书缺一不可
同样是上面的入口,选Apple Distribution。这里有个坑:mas(分发)构建实际要匹配两张证书。electron/build.js 的resolveMasSigningIdentities会同时找——
- 应用证书:名字匹配
Apple Distribution或3rd Party Mac Developer Application - 安装器证书:名字匹配
3rd Party Mac Developer Installer
两者缺一,构建直接抛错并列出钥匙串里现有的身份。
App ID 与 Bundle ID
Apple Developer Portal →Certificates, Identifiers & Profiles→Identifiers→App IDs,建一个与com.presenton.presenton匹配的 macOS App ID。若你用别的 ID,得回头改 electron/build.js 里的APP_ID。
两份 Profile 的落位与验证
Portal →Profiles→+里各建一个 macOS profile,下载后放进electron/build/:
| 用途 | Profile 类型 | 关联证书 | 落位文件名 | 备选文件名 |
|---|---|---|---|---|
MAS 开发(mas-dev) | macOS App Development | Apple Development | build/AppleDevelopment.provisionprofile | AppleDev.provisionprofile/AppDev.provisionprofile |
MAS 分发(mas) | Mac App Store | Apple Distribution | build/MacAppStore.provisionprofile | AppDistri.provisionprofile |
下载后立刻验证能否解码,别等构建时才发现问题:
cd electron # -D 表示 decode,检查 profile 是否为合法 DER 编码 security cms -D -i build/AppleDevelopment.provisionprofile security cms -D -i build/MacAppStore.provisionprofile两点提醒:Profile 通常按年过期,过期要重新生成并替换本地文件;真实 profile不要提交进 git,仓库里的MacAppStore.provisionprofile.replace_me占位文件就是为此留的位。
沙盒权限清单:entitlements 开了哪些口子
MAS 强制启用 App Sandbox,Presenton 的主进程权限写在 electron/build/entitlements.mas.plist。每一项对应一个具体的运行能力:
| 权限 key | 打开的能力 |
|---|---|
com.apple.security.app-sandbox | 启用 App Sandbox,MAS 硬性要求 |
com.apple.security.application-groups | 值为S6W5C54KL6.com.presenton.presenton,让应用与组件共享容器 |
com.apple.security.cs.allow-jit | 允许 JIT 编译,Electron 渲染进程依赖此项 |
com.apple.security.network.client | 发起出站网络连接 |
com.apple.security.network.server | 监听本地端口,支撑内置 Next.js / FastAPI 本地服务 |
com.apple.security.files.user-selected.read-write | 读写用户主动选定的文件(导入文档、导出 PPTX) |
com.apple.security.files.downloads.read-write | 读写下载目录 |
辅助进程与内置二进制走 electron/build/entitlements.mas.inherit.plist,只声明沙盒加com.apple.security.inherit,表示继承主进程的能力边界,不额外开洞。
一条命令跑通构建
所有命令都在electron/目录下执行。第一次用先跑初始化脚本,它会串起npm install、FastAPI 的uv sync、Next.js 依赖安装,以及导出运行时和 ImageMagick 的准备:
# 首次初始化,完成前后端依赖与运行时准备 npm run setup:env完整构建(推荐)
会重建 Next.js、FastAPI、导出运行时再打包,适合从零开始或改动较大时:
# MAS 开发:只能在开发 profile 注册的 Mac 上运行 PRESENTON_MAS_DEV_IDENTITY="Apple Development: Your Name (TEAMID)" \ npm run build:all:mas-dev # MAS 分发:用于上传 App Store Connect PRESENTON_MAS_DISTRIBUTION_IDENTITY="Apple Distribution: Your Org (TEAMID)" \ PRESENTON_APP_STORE_VERSION=1.0.0 \ npm run build:all:mas只重打包(资源已构建好)
跑过build:all后只想再走一遍 electron-builder 打包阶段,用dist:*系列:
PRESENTON_MAS_DEV_IDENTITY="Apple Development: Your Name (TEAMID)" \ npm run dist:mac:mas-dev PRESENTON_MAS_DISTRIBUTION_IDENTITY="Apple Distribution: Your Org (TEAMID)" \ PRESENTON_APP_STORE_VERSION=1.0.0 \ npm run dist:mac:mas注意:dist:*脚本依赖 electron/build.js 的资源就绪校验。它会逐一检查 FastAPI 二进制、LLM 模型元数据、Next.js standalone server、导出任务 runner、export-core 包以及导出用的 sharp 运行时,任何一项缺失都会在打包前报错,避免打出"启动不了内置服务"的坏包。
不走 App Store 的 DMG
只想要一份签名并公证(notarize)的 macOS 磁盘映像、跳过 App Store 审核时:
# 走 Developer ID Application 证书,需要 Apple 公证凭据 npm run build:all:mac:signed这条路径用的不是 MAS 证书,而是 Developer ID 证书,完整的证书准备与 notarytool 凭据存储见 macOS 直接分发指南。
版本号:为什么-beta后缀会让 mas 直接报错
当前 electron/package.json 的版本形如0.9.11-beta(带-beta后缀)。mas目标要求 App Store 版本号严格是三段点分整数,于是 electron/build.js 的getAppStoreBundleShortVersion做了两级回退:
- 优先读
PRESENTON_APP_STORE_VERSION,必须匹配/^\d+\.\d+\.\d+$/; - 没设时尝试从 package 版本里截
x.y.z前缀;截不出来(比如版本根本不是语义化)就抛Cannot derive an App Store version from package version。
build 号由getAppStoreBundleVersion读PRESENTON_APP_STORE_BUILD,匹配/^\d+(\.\d+){0,2}$/(1~3 段,如42或1.0.1),没设则回退到短版本号。所以带 beta 后缀的包,构建mas时这两个变量基本是必填:
# 版本号必须是三段整数;build 号可省略(默认取短版本号) export PRESENTON_APP_STORE_VERSION=1.0.0 export PRESENTON_APP_STORE_BUILD=42其余环境变量集中在这里,配命令时对着查:
| 变量 | 生效目标 | 含义 |
|---|---|---|
PRESENTON_MAC_TARGET | 脚本注入 | mas-dev/mas,配合上述脚本时别手动设 |
PRESENTON_MAS_DEV_IDENTITY | mas-dev | 开发签名身份,如Apple Development: 名字 (TEAMID) |
PRESENTON_MAS_DISTRIBUTION_IDENTITY | mas | 分发身份,如Apple Distribution: 组织 (TEAMID) |
PRESENTON_MAS_IDENTITY | mas | 上一项的别名 |
CSC_NAME | 两者 | 上面专属变量都没设时的回退 |
PRESENTON_APP_STORE_VERSION | mas | 商店版本号x.y.z;package 版本带后缀时必填 |
PRESENTON_APP_STORE_BUILD | mas | 商店 build 号,默认取短版本号 |
PRESENTON_CODESIGN_TIMESTAMP | mas | 设1恢复 codesign 时间戳,默认走--timestamp=none |
PRESENTON_CODESIGN_TIMESTAMP_RETRIES | mas | 时间戳失败重试次数,默认 4 |
后两个时间戳开关解释一下:本地 MAS 打包默认加--timestamp=none,是为了不依赖 Apple 时间戳服务(无网或受限网络下不挂起);真要时间戳就把PRESENTON_CODESIGN_TIMESTAMP设为1,重试次数用PRESENTON_CODESIGN_TIMESTAMP_RETRIES调。
产物落点与上传入口
所有产物统一输出到electron/dist/,具体子目录随架构(arm64/x64)变化,典型布局:
electron/dist/ mas-dev-arm64/ # mas-dev:未签名或开发签名的 .app mas-arm64/ # mas:分发签名的 .app Presenton-<version>.pkg # 用于上传 App Store Connect 的 MAS 安装包 Presenton-<version>.dmg # 签名并公证的直接分发 DMG把mas构建产出的.pkg传进 App Store Connect,就进入审核与发布流程。
build.js 在打包前替你拦下的三个坑
这几处是 electron/build.js 里最有工程价值的部分,理解它们能少踩很多隐性错误:
资源就绪校验。collectMissingBundleResources把上面dist:*提到的五项资源列成清单,打包前后各查一遍(afterPack阶段还会再确认一次装进.app的副本),缺项就列出路径并停手。
签名身份解析。mas-dev的身份直接取PRESENTON_MAS_DEV_IDENTITY,没设回退CSC_NAME。mas更复杂:resolveMasSigningIdentities会跑security find-identity -v读全钥匙串身份,身份限定词依次从PRESENTON_MAS_DISTRIBUTION_IDENTITY、PRESENTON_MAS_IDENTITY、CSC_NAME取,最后自动发现匹配的证书对。它还会拒绝把 Apple Development 这类开发身份用于分发构建,防止你拿错证书打分发包。
codesign 预检与平台限制。分发构建启动前,assertCodesignCanUseIdentity会拿一个临时文件用选中的分发身份实际签一次,超时(通常是 macOS 在等钥匙串/私钥授权)就给出"解锁登录钥匙串并允许 codesign 访问私钥"的明确提示。另外resolveProvisioningProfile在非 darwin 平台会直接抛MAS builds must be run on macOS——Apple 签名工具只在 macOS 上可用,这条没有绕过办法。
图标与 .icns
默认 macOS 图标来自electron/resources/ui/assets/images/presenton_short_filled.png。想给 App Store 打包换正式.icns,把它放到electron/build/icon.icns,并同步改 electron/build.js 里mac配置下的icon字段(当前指向build/icon.icns)。生成图标集用的源 PNG 在electron/build/icon.iconset/目录里。
内测沙盒的四条红线
- MAS 签名应用必须用 MAS 目标构建(
mas或mas-dev),普通 DMG 构建的沙盒兼容性并不等价; mas-dev构建只能跑在开发 profile 注册的 Mac 上,适合做 TestFlight 式的内测;mas(分发)构建通常本地起不来,它是给 App Store Connect 处理和发布用的;mas-dev签名用--timestamp=none,本地签名不依赖网络时间戳服务器,无网也不会挂起。
报错对照表
| 报错 | 原因与解法 |
|---|---|
Missing MAS development/distribution provisioning profile | 把对应目标的.provisionprofile放进electron/build/,脚本会按候选文件名逐一匹配 |
macOS 提示 profile 无法解码(could not decode) | 从 Developer Portal 重新下载替换;真实 profile 不要提交 git |
Cannot derive an App Store version from package version | 设PRESENTON_APP_STORE_VERSION为三段整数,如1.0.0 |
MAS builds must be run on macOS | 在装了 Xcode 命令行工具的 Mac 上构建(xcode-select --install) |
| .app 内 FastAPI / 导出二进制不可执行 | afterPack钩子已对 FastAPI 二进制chmod 755并剪掉与目标架构不符的 prebuild 目录;签名仍失败时检查 entitlements 是否放行Contents/Resources/app/resources/下的辅助程序 |
参考
- macOS 开发 README:全部 macOS 构建目标的快速参考
- macOS 直接分发指南:Developer ID 证书、公证与 DMG 验证流程
【免费下载链接】presentonOpen-Source AI Presentation Generator and API (Gamma, Canva, Beautiful AI, Decktopus, Presentations AI Alternative)项目地址: https://gitcode.com/GitHub_Trending/pr/presenton
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考