Presenton Mac App Store 构建实战:MAS 打包的证书、Profile 与脚本完整避坑指南
【免费下载链接】presentonOpen-Source AI Presentation Generator and API (Gamma, Canva, Beautiful AI, Decktopus, Presentations AI Alternative)项目地址: https://gitcode.com/GitHub_Trending/pr/presenton
把 Electron 应用送进 App Store,最劝退的往往不是写代码,而是证书和 provisioning profile 这一套 Apple 的规矩。Presenton 是一个内置 Next.js 前端与 FastAPI 后端的 AI 演示文稿生成器,仓库已经把 Mac App Store 构建的工程化配置铺好了:沙盒 entitlements 文件、build.js构建脚本、npm 目标脚本全部就位,你要做的只是补齐 Apple 开发者账号侧的四样东西,然后跑一条命令。这篇按"一次真实构建"的动线走:先备好材料,再执行打包,最后处理报错。
先扫两张表:目标、命令与环境变量
这节解决"最高频信息 30 秒拿到"的问题,后面所有环节都是这两张表的展开。
构建目标与所需证书:
| 构建目标 | 用途 | npm 命令(在electron/下执行) | 所需证书 |
|---|---|---|---|
dmg | 不走 App Store 的直接下载分发 | npm run build:all:mac:signed | Developer ID Application + 公证凭据 |
mas-dev | 注册 Mac 上的沙盒内测 | npm run build:all:mas-dev | Apple Development |
mas | App Store 提交 | npm run build:all:mas | Apple Distribution + 3rd Party Mac Developer Installer(两张证书缺一不可) |
三个目标全部由PRESENTON_MAC_TARGET环境变量驱动,上面三个 npm 脚本内部已经设好,你不必手动指定。两个关键身份标识写死在 build.js 顶部:Bundle ID 为com.presenton.presenton,Team ID 为S6W5C54KL6(同时通过mac.extendInfo.ElectronTeamID写进应用)。
环境变量速查:
| 变量 | 用于 | 说明 |
|---|---|---|
PRESENTON_MAC_TARGET | 全部 | 由 npm 脚本设置,用脚本时别手动设 |
PRESENTON_MAS_DEV_IDENTITY | mas-dev | 开发签名身份,如Apple Development: Your Name (TEAMID) |
PRESENTON_MAS_DISTRIBUTION_IDENTITY | mas | 分发身份,如Apple Distribution: Your Org (TEAMID) |
PRESENTON_MAS_IDENTITY | mas | 分发身份的别名 |
CSC_NAME | 两种 MAS 目标 | 目标专属变量没设时的回退 |
PRESENTON_APP_STORE_VERSION | mas | App Store 版本号(x.y.z),package 版本带-beta后缀时必填 |
PRESENTON_APP_STORE_BUILD | mas | App Store build 号,不设则默认取短版本号 |
PRESENTON_CODESIGN_TIMESTAMP | mas/dmg | 设为1恢复 codesign 时间戳(默认本地打包用--timestamp=none) |
PRESENTON_CODESIGN_TIMESTAMP_RETRIES | mas/dmg | 时间戳失败重试次数,默认 4 |
准备阶段:四样材料一次备齐
这节解决"构建前到底要向 Apple 要什么、本地要放什么"的问题。材料顺序按 Apple 开发者工作流排:证书 → App ID → Profile → entitlements。
在 Xcode 里生成两张证书
为什么是两张:Apple Development 用于mas-dev沙盒内测;Apple Distribution 用于mas商店构建。而mas构建实际要签名两个东西——应用本体和.pkg安装包,所以 build.js 的resolveMasSigningIdentities会同时找应用证书(Apple Distribution或3rd Party Mac Developer Application)与安装包证书(3rd Party Mac Developer Installer),缺一就抛错退出。
- 打开 Xcode →Settings→Accounts→ 选择你的团队 →Manage Certificates。
- 点+,先创建Apple Development(给内测构建用)。
- 再点+,创建Apple Distribution(给商店构建用;安装包证书
3rd Party Mac Developer Installer通常随团队在 Portal 上签发,导入钥匙串即可)。
在 Portal 注册一个匹配的 App ID
去 Apple Developer Portal →Certificates, Identifiers & Profiles→Identifiers→App IDs,创建一个 macOS App ID,取值填com.presenton.presenton。如果你用自己的 ID,记得同步改掉 build.js 里的APP_ID,否则签名和 profile 会互相不认识。
下载两个 Provisioning Profile 放进 electron/build/
Provisioning profile 可以理解为"设备白名单通行证":它把证书、App ID 和允许的机器绑在一起,Apple 服务器凭它验证这个构建是否合法。两个目标各需要一份,对应关系如下:
| Profile | 类型 | 绑定证书 | 保存为 |
|---|---|---|---|
| 开发 profile | macOS App Development | Apple Development | electron/build/AppleDevelopment.provisionprofile |
| 商店 profile | Mac App Store | Apple Distribution | electron/build/MacAppStore.provisionprofile |
两个细节:
- 构建脚本按候选文件名列表查找,
mas-dev还接受AppleDev.provisionprofile、AppDev.provisionprofile作回退;mas还接受AppDistri.provisionprofile。 - 真实 profile 不要提交进 git——仓库里那个
MacAppStore.provisionprofile.replace_me占位文件就是让你只提交"待替换"状态用的。
放入后先验证能否解码:
cd electron # 两个文件都应能解码出 plist,解码失败说明文件不对或已损坏 security cms -D -i build/AppleDevelopment.provisionprofile security cms -D -i build/MacAppStore.provisionprofileProfile 通常按年过期,到期后重新下载替换本地文件即可。
看清 entitlements 里每个开关管什么
这节解决"沙盒应用为什么能跑起来"的问题。entitlements 是"沙盒权限开关清单",entitlements.mas.plist 逐项声明了主应用的能力:
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:允许发起和监听连接——Presenton 内置的 Next.js 与 FastAPI 本地服务全靠这两项;com.apple.security.files.user-selected.read-write:读写用户主动选定的文件(导入文档、导出 PPTX 的路径);com.apple.security.files.downloads.read-write:读写下载目录。
辅助进程的 entitlements.mas.inherit.plist 只有两项:app-sandbox加com.apple.security.inherit,意思是"继承主进程的能力边界,不额外开洞"。
执行阶段:三条构建路径
这节解决"命令怎么跑、产物落在哪"的问题。所有命令都在electron/目录下执行;首次使用先跑npm run setup:env,它会串起npm install、FastAPI 的uv sync、Next.js 依赖安装以及导出运行时与 ImageMagick 的准备。
完整构建(推荐首发路径)
会重建 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 # 当前 package.json 版本带 -beta 后缀,PRESENTON_APP_STORE_VERSION 是必填项 PRESENTON_MAS_DISTRIBUTION_IDENTITY="Apple Distribution: Your Org (TEAMID)" \ PRESENTON_APP_STORE_VERSION=1.0.0 \ npm run build:all:mas只重跑打包阶段
资源已经构建好、只想再跑一次 electron-builder 打包时(比如刚改了签名身份):
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:*脚本依赖 build.js 里的资源就绪校验——它会逐一检查 FastAPI 二进制、LLM 模型元数据、Next.js standalone server、导出任务 runner 与 export-core 包,任何缺失都会提前报错,避免打出"内置服务起不来"的坏包。
不走 App Store:直接出签名 DMG
只想产出签名并公证的磁盘映像、绕过商店审核时:
# 使用 Developer ID Application 证书,需 Apple 公证凭据 npm run build:all:mac:signed这条路径的 Developer ID 证书、notarytool 凭据存储与 Gatekeeper 验证细节见 直接分发指南。
带 beta 后缀的版本号坑
当前仓库 package.json 的版本是0.9.11-beta,带-beta后缀。mas目标的版本号推导逻辑(build.js 中的getAppStoreBundleShortVersion)是:
- 优先读
PRESENTON_APP_STORE_VERSION,必须匹配x.y.z三段点分整数,否则直接抛错; - 未设置时尝试从 package 版本截取
(\d+)\.(\d+)\.(\d+)前缀; - 截取失败(版本号根本不是语义化格式)就抛 "Cannot derive an App Store version from package version"。
PRESENTON_APP_STORE_BUILD走同样的校验风格(1~3 段点分整数,如42或1.0.1),不设则回退为短版本号。所以 beta 版本构建mas时,最省事的写法:
export PRESENTON_APP_STORE_VERSION=1.0.0 # 商店版本号,三段点分整数 export PRESENTON_APP_STORE_BUILD=42 # build 号,可选产物都落在 electron/dist/
路径随架构(arm64/x64)略有不同,典型布局:
electron/dist/ mas-dev-arm64/ # 开发签名的 .app,仅限注册 Mac 运行 mas-arm64/ # 分发签名的 .app,供 App Store Connect 处理 Presenton-<version>.pkg # 上传 App Store Connect 的 MAS 安装包 Presenton-<version>.dmg # 签名并公证的直接分发 DMGmas构建产出的.pkg就是最终上传 App Store Connect 的东西。
排错:五类高频报错的对照处理
这节解决"构建失败时怎么快速定位"的问题。每条按"报错长什么样 → 为什么会这样 → 一步修复"展开。
| 报错信息(节选) | 原因 | 修复动作 |
|---|---|---|
Missing MAS development/distribution provisioning profile. Expected: ... | electron/build/里没有该目标对应的 profile 文件 | 按上表把正确的.provisionprofile放入electron/build/,报错信息里列出的就是它期望的文件名 |
Found MAS ... provisioning profile, but macOS could not decode it: ... | 文件存在但security cms -D与openssl cms -verify都解不开——文件损坏、传错或占位文件 | 从 Developer Portal 重新下载对应 profile 覆盖本地文件;别把真实 profile 提交进 git |
Cannot derive an App Store version from package version "0.9.11-beta" | package 版本提取不出x.y.z三段整数 | 设置PRESENTON_APP_STORE_VERSION=1.0.0再跑构建 |
MAS development builds must be run on macOS because Apple signing tools are required. | 在非 macOS 平台(如 Linux CI)上跑了 MAS 目标 | 换到有 Xcode 命令行工具(xcode-select --install)的 Mac 上执行 |
Missing MAS signing identity.后列出已有身份清单 | 钥匙串里缺应用证书或安装包证书之一,或身份变量指向了开发证书 | 按报错清单补装缺失证书到钥匙串;分发构建不能使用 Apple Development 等开发身份,脚本会显式拒绝 |
沙盒内辅助程序不可执行(FastAPI / 导出二进制打不开):build.js 的afterPack钩子会先对打包后的二进制执行chmod 755并清理与目标架构不符的原生 prebuild 目录;如果之后仍签名失败,回到准备阶段那两份 entitlements,确认沙盒应用被允许执行Contents/Resources/app/resources/下的辅助程序。
进阶:身份解析、时间戳、图标与内测限制
这节面向要深度定制构建流程的读者,日常跑通前两个阶段可以跳过。
签名身份解析与构建前预检。mas目标的身份解析链是:PRESENTON_MAS_DISTRIBUTION_IDENTITY→PRESENTON_MAS_IDENTITY→CSC_NAME→ 自动发现。脚本用security find-identity -v读全钥匙串,取身份限定词后自动匹配"应用证书 + 安装包证书"这对组合,并拒绝开发身份混入分发构建。正式启动打包前还会执行一次codesign预检:在临时文件上用选中的分发身份真签一次,30 秒超时——超时通常意味着 macOS 在等钥匙串/私钥授权弹窗,此时按提示解锁登录钥匙串并允许 codesign 访问 Apple Distribution 私钥即可。
时间戳开关。本地 MAS 打包默认给 codesign 追加--timestamp=none,不依赖 Apple 时间戳服务,无网或受限网络下不会挂起。需要时间戳时设PRESENTON_CODESIGN_TIMESTAMP=1恢复;时间戳偶发失败的重试次数由PRESENTON_CODESIGN_TIMESTAMP_RETRIES控制(默认 4 次,指数退避)。
图标。默认 macOS 图标是electron/resources/ui/assets/images/presenton_short_filled.png。要为商店提供正式.icns,放到electron/build/icon.icns并同步更新 build.js 的mac.icon字段;生成图标集的源 PNG 在electron/build/icon.iconset/。
本地沙盒测试的四条边界。
- MAS 签名的应用必须由
mas或mas-dev目标产出,普通 DMG 构建不具备同等的沙盒兼容性; mas-dev构建只能在开发 profile 里注册过的 Mac 上启动,适合 TestFlight 式内测;mas分发构建通常无法在本地直接启动,它的归宿是 App Store Connect 的处理与发布流水线;mas-dev签名带--timestamp=none(见上时间戳开关),本地签名与网络状态无关。
下一步:把 .pkg 交给 App Store Connect
构建跑通后,动作只剩一个:把electron/dist/下mas产出的Presenton-<version>.pkg通过 App Store Connect 的上传入口提交,等待审核后发布。之后每次发版,记住固定三步:确认 profile 未过期 → 递增PRESENTON_APP_STORE_VERSION与 build 号 → 重跑build:all:mas。
延伸阅读(仓库内相对路径):
- macOS 开发 README——全部构建目标速查,含
npm run dev与 notarytool profilepresenton-notary说明 - Mac App Store Setup——本文对应的官方设置文档
- Direct Distribution——Developer ID 证书、公证与 DMG 验证流程
- build.js——签名身份解析、profile 校验与版本号推导的完整实现
【免费下载链接】presentonOpen-Source AI Presentation Generator and API (Gamma, Canva, Beautiful AI, Decktopus, Presentations AI Alternative)项目地址: https://gitcode.com/GitHub_Trending/pr/presenton
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考