补记说明:本文于 2026 年 10 月 25 日整理并首次发布。页面日期是这份经验的归档日期,历史案例与当前开放状态分别说明。

“两个包都发了。”这句话,最近我越来越不敢随口说。

咫尺是我正在做的一款双人互动 App。给它发更新时,我会从同一份代码分别打 iPhone 和 Mac 包。有一批,iPhone 已经可以给外部测试的人用,Mac 也上传成功、处理成有效构建了,却还没到外部测试者手里。

原因很具体:前一个 Mac 构建还在等待 Beta 审核。新包可以上传、可以进入内部测试,提交外部审核却被挡住了。发布记录里留下了一个报错:ANOTHER_BUILD_IN_REVIEW。

如果你也准备把 App 发给朋友试用,这篇可以帮你先分清:更新还卡在哪里,该向谁确认。

这篇接着十月初的上架笔记往后写。那篇解决账号和第一次签名,这篇讲有了持续迭代以后,怎样分清“我做出了一个包”和“别人已经拿到了这个版本”。文中的 TestFlight 是 Apple 用来分发测试版的工具。咫尺仍在受邀内测,这些经历还不能当成已经走完 App Store 正式上架。

01 / 更新卡在哪一步
上传成功以后,还没有到更新的终点 从做包到上传和处理,再分内部测试与外部测试两路;两路的分发条件分别核对。 做出软件包 本机归档、签名与导出 上传给 Apple 上传成功,仍需等待处理 Apple 处理完成 接下来还要看分发渠道 内部测试 分配到内部组 外部测试 审核、分组 通知测试者 最后确认:对方实际拿到了哪一版
分发流程示意。连线表示接续关系;内部与外部是两路测试分发,不是必须依次走完的两个阶段。具体以当次审核和测试组状态为准。

先看人能拿到哪一版,再看我上传了哪一版#

我翻到的 10 月 24 日发布记录里,iPhone 的新包已经进入外部测试;Mac 的新包虽然有效,也进入了内部组,但旧构建还在等审核。我选择保留旧审核,没有为了提交新包就让它过期。

因此,对外说版本时,至少要分开记:

进到哪一步这一步实际证明了什么
本机归档成功有一个归档产物,接下来还要导出和核验
签名、导出通过形成了对应渠道的安装或上传包
上传成功Apple 收到了这次提交
Apple 处理通过构建可进入后续测试或审核流程
内部组可测试这个内部组的人可以取得构建
外部组可测试这个外部组的人可以取得构建

Apple 的说明也把上传后的处理单独列出:上传之后还要处理,构建才会出现在 App Store Connect;构建号用来区分同一 App 的不同构建。Apple:上传构建

外部测试还要看组和审核状态。同一版本同时只能有一个构建在等待审核;是否通知测试者,也有自己的步骤。我的那次报错,正好卡在这里。Apple:邀请外部测试者

现在我更愿意写“iPhone 外部测试可用,Mac 新包仅内部可用”。多写几个字,下一次就不用猜谁拿到了哪一版。

App 加了小组件和手表,签名也跟着多了几份#

最初,我容易把签名理解成给一个 App 盖章。后来咫尺加了小组件、通知扩展、分享扩展和 Apple Watch,才发现安装包里面还有许多要分别核对的目标。

这次手表接入就碰到了:工程已经能编译,Apple 那边的 App ID 和 App Group 关联却没有随之自动就绪。账号持有人补好对应关联之后,签名才过。

我因此把检查放到了产物上:主 App 和扩展的版本是否一致,身份是不是从同一份配置推出来的,应该嵌入的扩展有没有进去,签出来的权限和描述文件是否对应。Mac 包不该带上的 iPhone 分享扩展,也要检查确实没有带进去。

咫尺的 Mac 版是原生 SwiftUI macOS App,复用部分代码,沿用既有的应用身份。它仍有自己的沙盒和权限配置。主 App 能签,并不能替里面每个扩展回答这些问题。

给别人复用这段经验,我会建议先画一张很小的表:每个目标叫什么、给哪个平台、嵌在哪里、需要什么能力。遇到签名失败,沿着表找到出问题的那一项,比不断重试整个归档更有方向。

02 / 不能只看主 App
主 App 和扩展要分别检查 把主 App、小组件通知等扩展和配套手表应用分开,核对各自身份、版本与权限。 一个安装包,里面不止一个要核对的部分 主 App 应用身份 · 版本 · 权限 小组件、通知等扩展 各自身份 · 嵌入位置 · 权限 配套手表 App 手表平台 · 身份关联 · 版本
组件检查示意,不是安装包的精确目录。各平台按需要取舍扩展;Mac 版不应把仅给 iPhone 的扩展一起带上。

有的警告不挡上传,却影响以后怎么查崩溃#

音视频依赖又让我认识了另一类问题:缺 dSYM。

dSYM 保存调试符号,可以帮助把崩溃里的地址还原成更容易定位的代码位置;它必须和那次构建的二进制对应。随便找一个同名文件放进去没有用。Apple:查找缺失的调试符号

咫尺用到的两个音视频原生库,上传时出现过缺符号警告。iPhone 的构建流程后来补了同版本源码构建、UUID 匹配和符号检查;Mac 对应的符号还没补齐,发布记录里仍留着警告。Mac 包当时能上传,但这些库的崩溃定位能力有缺口。

我想保留的经验是:遇到警告,先弄清它影响什么,再决定如何处理。能上传、能安装、出问题后能定位,应该分别核对。不能因为当下没挡住发布,就把警告从记录里抹掉。

Mac 发给别人,还有不同的路#

咫尺这次通过 TestFlight 给 Mac 测试者发包,所以检查的是商店分发所需的 App、安装包签名和平台记录。

如果选择在商店外直接分发 Mac 软件,还会遇到 Developer ID、Apple 公证和 Gatekeeper 下的启动检查。它是另一条交付路径,不能拿 TestFlight 上传成功来证明,也不能拿本机调试签名代替。Apple:在 Mac App Store 之外分发

因此,我现在会在写打包脚本之前,先写清这一次要到哪里:本机验证、内部测试、外部测试,还是正式分发。脚本的退出条件跟着这个目标走。

下一次发版,我会留下这几项#

源码版本、平台、展示版本与构建号、导出产物、Apple 处理状态、测试组状态,再加一条实际安装反馈。iPhone 和 Mac 分开记;有后端变化,就把对应服务版本也记下来。

我会把其中最常用的部分写成一张小回执。下面只是自编的格式示例,没有填入真实账号或测试组信息:

要回答的问题示例写法
这次给谁iPhone 的受邀测试者
他们现在能拿到什么当前外部组中可取得的测试构建
新包到了哪一步Mac 新包已处理,外部分发仍需确认
上一版是否仍然可用保留上一可用构建,单独记有效状态
下一步是谁做什么核对审核结果,再确认测试组可取得的版本

完整源码、签名材料和渠道身份可以在私有发布记录里对应,对外解释通常不需要把它们全部贴出来。最值得让测试者看到的是平台、可用状态和接下来该怎样更新。

收到“我这边还没有更新”时,也可以按这个顺序排查:先确认他用的哪一端,再确认加入的是不是这次分发范围,最后才回头看上传记录。把用户所在的那条路找对,比对着一条“上传成功”反复重试更有效。

还有一种情况要提前说清:同一平台同时有内部测试者和外部测试者,两个人看到不同版本也可能符合当时的分发状态。版本提示应当面向这个人真正能取得的包,避免让他来回刷新一个尚未向自己开放的版本。

尤其是 App 里的更新提示,应该指向目标用户真的能取得的版本。上传了一份更新的包,不代表现在就该让所有人去下载它。

这些记录不能替代真机测试,但能让我在收到“怎么还没更新”的时候,先看清卡在哪一步,再决定下一步做什么。

本文整理于 2026 年 10 月 25 日,案例来自此前的发布记录,没有在写作时重新打包、提交审核或核验当前审核队列。签名和分发结果也不能代表音视频、系统通知等功能已经逐项通过真机验收。

产品当前的安装范围见咫尺公开介绍。这里发布的是经验文章,不会触发 App 打包、签名或渠道审核。