RemoteMac 2026.09.06

远程 Mac SSH 断线后打包会停吗?2026 持续任务方案

Archive 运行到一半时 SSH 断开,终端消失并不代表构建一定停止,也不代表产物仍然可用。本文按临时构建、长时间 Archive、重复发布和主机重启等场景,给出可重连会话、日志取证、签名验证与后台任务恢复方案。

Archive 运行到一半时本地网络中断,重连后既找不到终端输出,也不确定是否还能继续上传。

最快的处理方式是:远程 Mac SSH 断线打包不能直接依赖前台终端;临时任务放进可重连会话并单独保存日志,重复发布交给 CI Runner 或受管理的后台作业,涉及 Simulator、Keychain 或图形授权时再额外验证用户登录会话。

这篇文章适合以下几类人:

  • 没有本地 Mac、通过 SSH 执行 iOS Archive、测试或上传的 Windows / Linux 开发者。
  • 希望让远程 Mac 承担夜间构建、定时测试或 TestFlight 发布的小团队。
  • 网络中断后无法判断任务究竟继续、失败,还是仅仅失去了日志的环境维护者。

01 先按任务场景判断:SSH 断开不等于构建结果

macOS 的 Remote Login 只是提供 SSH 访问入口。Apple 官方说明中,开启 Remote Login 后可以使用 ssh username@hostname 登录 Mac,但这并没有承诺由该 Shell 启动的所有子进程都能脱离会话继续运行。Remote Login 设置与 SSH 登录格式

因此,SSH 断开后通常要区分 3 种结果

断线后的状态 表面现象 正确判断方式 后续动作
任务终止 终端消失,进程不再存在 检查进程、退出码和日志末尾 清理临时目录后重新构建
任务继续但日志丢失 进程仍在,原终端无法恢复 检查独立日志、产物目录和文件更新时间 等待结束,再根据产物验收
进程存在但构建阻塞 进程还在,日志长时间不变化 检查 CPU、磁盘、网络、Simulator 或签名等待 先保留证据,再决定是否终止

你不能用“终端窗口还在刷新”代替进程检查,也不能用“进程还存在”代替产物检查。对 xcodebuild 来说,真正有价值的证据至少包括标准输出、错误输出、退出状态、xcresultxcarchive,以及最终导出目录。

Apple 的命令行工具文档确认,xcodebuild 用于构建 Xcode 项目和工作区;同时,命令行工具需要安装 Xcode,并将目标 Xcode 设置为当前开发者目录。Xcode 命令行工具参考

注意: 不要一重连就执行第二次 Archive。先确认原任务是否仍在运行,否则可能覆盖日志、重复使用构建号,甚至把旧的导出文件误认为新产物。

02 临时任务采用可重连会话,并把证据写到磁盘

手动执行一次 Build、Test 或 Archive 时,可重连会话适合解决“SSH 连接断了,但任务仍需观察”的问题。它不是完整的 CI 系统,不能替代任务排队、密钥管理和重启恢复,但比直接在前台 Shell 中运行更容易恢复。

先创建统一的工作目录,所有用户名、主机地址、项目名、Scheme、Bundle ID、Team ID 和密钥都使用占位符:

export JOB_ROOT="$HOME/ios-jobs/<JOB_ID>"
export LOG_DIR="$JOB_ROOT/logs"
export OUT_DIR="$JOB_ROOT/output"

mkdir -p "$LOG_DIR" "$OUT_DIR"

然后把构建命令放入可重连会话。下面以 tmux 为例,重点不在工具本身,而在于让任务拥有独立的启动上下文:

tmux new -s ios-build-<JOB_ID>

在会话中运行一个包装脚本,而不是直接敲一长串命令:

set -o pipefail

/usr/bin/xcodebuild \
  -workspace "<WORKSPACE_PATH>/<PROJECT>.xcworkspace" \
  -scheme "<SCHEME>" \
  -configuration Release \
  -destination "generic/platform=iOS" \
  -archivePath "$OUT_DIR/<APP>.xcarchive" \
  archive \
  > >(tee "$LOG_DIR/archive.stdout.log") \
  2> >(tee "$LOG_DIR/archive.stderr.log" >&2)

status=$?
printf '%s\n' "$status" > "$LOG_DIR/archive.exit"
printf '%s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" > "$LOG_DIR/archive.finished-at"

exit "$status"

Apple 的文档将 archiveexportArchive 明确作为不同动作;官方示例也使用 xcodebuild -exportArchive 从 Archive 导出可分发版本。Apple 的 Xcode Archive 与导出流程

断开 SSH 前,不要关闭会话中的任务;直接退出 SSH 即可。重新登录后,按以下顺序查看:

tmux ls
tmux attach -t ios-build-<JOB_ID>

tail -n 80 "$HOME/ios-jobs/<JOB_ID>/logs/archive.stdout.log"
tail -n 80 "$HOME/ios-jobs/<JOB_ID>/logs/archive.stderr.log"

cat "$HOME/ios-jobs/<JOB_ID>/logs/archive.exit"
ls -ld "$HOME/ios-jobs/<JOB_ID>/output/"*

如果退出状态为 0,它表示命令成功;Apple 在 Xcode Cloud 的环境变量文档中也将 0 定义为 xcodebuild 成功退出的状态。Xcode 构建退出状态说明

03 Archive、导出和上传必须拆成独立阶段

长时间发布任务最容易出错的地方,是把 Archive、导出、上传和 App Store Connect 后台处理写成一条无法取证的命令。更稳妥的边界如下:

阶段 主要输入 必须保存的证据 网络中断后的处理
Archive 源码、Workspace、Scheme、签名上下文 xcarchive、构建日志、退出码 有完整 Archive 时不要重复构建
exportArchive xcarchiveExportOptions.plist 导出目录、导出日志、退出码 可从现有 Archive 重新导出
二进制上传 .ipa 或导出包 上传日志、交付记录、构建号 先核对版本和构建号,再重试
App Store Connect 处理 已上传的构建 App Store Connect 中的处理状态 上传成功不等于后台处理完成

Apple 的发布流程要求先创建 Archive,再根据分发方式导出或上传;上传后还需要等待 App Store Connect 完成验证和处理。App Store Connect 发布流程

可以把每个阶段都写入独立目录:

<JOB_ROOT>/
├── logs/
│   ├── archive.stdout.log
│   ├── archive.stderr.log
│   ├── export.stdout.log
│   └── upload.stdout.log
├── output/
│   ├── <APP>.xcarchive
│   └── exported/
└── state/
    ├── archive.exit
    ├── export.exit
    └── upload.receipt

上传命令返回成功,只能证明客户端完成了交付动作,不能证明 App Store Connect 后台已经处理完毕。若网络恢复后发现已有相同版本和构建号的上传记录,应先查询交付状态,再决定是否重新执行上传。

04 用决策表选择可重连终端、CI Runner 或 launchd

不同场景不应强行使用同一种方案。我们建议先按照任务频率、是否需要无人值守,以及是否必须跨主机重启恢复来选择:

使用场景 推荐方案 关键原因 不适合的情况
偶发 Build、Test、Archive 可重连终端 配置快,便于人工观察 夜间无人值守、频繁提交
长时间 Archive 或导出 可重连终端 + 独立日志 断线后能恢复查看,产物边界清晰 需要自动排队和失败重试
每次提交自动构建 CI Runner 启动上下文、状态和日志更明确 没有稳定在线主机或签名环境
夜间测试、定时发布 CI Runner 或受管理后台作业 不依赖个人电脑和人工 SSH 需要频繁临时修改任务参数
主机重启后自动拉起服务 launchd 管理 Runner 或作业 可定义启动账号、路径和日志 把它误当成“自动恢复中断构建”

launchd 可以通过 ProgramArguments 定义启动参数,通过 KeepAlive 控制作业是否持续运行,也可以使用定时或目录触发方式。Apple 的 launchd 作业配置说明

KeepAlive 只负责让作业保持运行,不会自动恢复一个已经损坏的 Archive,也不会替你判断构建号是否已经上传。后台服务必须自己写入开始标记、结束标记、退出码和产物路径。

05 处理 Simulator、Keychain 与图形会话的额外风险

纯命令行构建与需要用户上下文的任务不能混为一谈。SSH 登录产生的是远程登录会话,不一定等价于本地用户已经登录的图形会话;Apple 关于进程会话的说明也区分了 root session、login session 和 console session,远程登录连接主要包含 Shell 级进程。Apple 的进程与登录会话说明

建议把故障分成以下几类:

  • 纯命令行 Build 或 Archive: 重点检查 Xcode 路径、依赖缓存、磁盘空间、日志和退出码。
  • Simulator 测试: 检查目标设备是否存在、Simulator 服务是否响应,以及测试结果是否生成了 xcresult。Apple 的测试文档确认,测试可以通过 Xcode 或终端中的 xcodebuild 执行。Xcode 测试与结果解释
  • Keychain 签名: 检查当前用户能否访问证书和私钥,不能因为 SSH 断线就直接放宽 Keychain 权限。
  • 图形授权操作: 检查是否需要已登录的桌面会话、弹窗确认或用户交互。

任何终止进程、修改 Keychain ACL、调整后台权限或注册系统作业的操作,都要先记录影响范围。例如,终止构建只应针对明确的 <JOB_ID>,并保留原日志;修改签名权限前要导出当前配置,完成验证后能够恢复原设置。

经验: “进程还在”只能证明某个 PID 尚未退出,不能证明 Simulator、Keychain 或图形授权仍然可用。远程签名任务尤其要做一次“用户退出后再构建”的对照测试。

06 用三次验收测试判断环境能否长期承担打包

不要等到真实发布时才发现 SSH 断线会破坏任务。我们建议为远程 Mac 建立一份可重复的验收记录,每次更换 macOS、Xcode、签名资产或交付环境后重新执行。

第一次:构建中主动断开 SSH

  1. 启动一个不会上传到生产环境的测试 Archive。
  2. 确认日志文件已经开始写入,并记录任务 ID。
  3. 主动关闭本地 SSH 连接,不关闭远程任务会话。
  4. 等待任务自然结束后重新登录。
  5. 检查进程状态、完整日志、退出码、xcarchive 和日志结束标记。

第二次:任务运行时退出用户会话

  1. 使用与正式构建相同的账号启动测试。
  2. 退出图形用户会话,或者切换到另一个用户。
  3. 分别测试纯命令行 Archive、Simulator 测试和签名任务。
  4. 对比哪些任务继续、哪些任务阻塞、哪些任务因 Keychain 或图形上下文失败。
  5. 恢复原登录状态,并记录回退方法。

第三次:主机重启后验收服务

  1. 先保存当前 Runner 或后台作业配置。
  2. 重启远程 Mac,确认服务是否由 launchd 重新加载。
  3. 检查 Xcode 开发者目录、工作目录、环境变量和日志权限。
  4. 提交一个不会上传的测试构建。
  5. 验证服务状态、任务状态、退出码和产物是否可查询。

如果采用 Runner,重点不是只看服务是否显示“运行中”,还要确认它能接收任务、启动正确账号,并在任务失败后留下日志。Apple 的 launchd 文档可以帮助确认作业文件位置、启动参数和保持运行策略,但具体构建是否适合无人值守,仍必须通过上述验收验证。

07 断线恢复检查清单

  • [ ] 已为每次构建生成唯一的 <JOB_ID>,并使用独立日志目录。
  • [ ] 标准输出与错误输出没有只保存在 SSH 终端窗口中。
  • [ ] Archive、导出、上传分别拥有独立的退出码和完成标记。
  • [ ] 已记录 xcarchivexcresult、导出目录和交付记录的位置。
  • [ ] 断开 SSH 后,能重新定位任务会话或后台作业。
  • [ ] 重连时会先检查原任务,而不是立即重复执行整条流水线。
  • [ ] 已测试用户退出后,Keychain、Simulator 和签名任务的实际表现。
  • [ ] 已测试主机重启后服务是否自动加载。
  • [ ] 终止进程、修改权限或注册作业前,已有影响范围和回退记录。
  • [ ] 真实发布前,已经用测试构建验证过版本号和构建号不会重复。

如果你的项目还处于一次性手动构建阶段,可以先参考 远程 Mac 的基础使用入口,把可重连会话和日志留存做好;当夜间测试或多人提交开始增加,再把任务迁移到常驻 Runner。需要长期在线环境时,可进一步对照 远程 Mac 租赁方案 的周期和使用方式,而不是继续依赖个人电脑临时开机。

08 当前设备与远程 Mac 方案的取舍

如果当前方案是个人 Windows / Linux 电脑加临时 SSH 连接,常见缺点有 3 个:电脑关机后无法接收任务;前台 Shell 断线后容易丢失日志;没有固定的服务账号和重启验收流程时,夜间构建很难确认是否真的完成。把 Mac 临时放在办公室或家里也会增加电源、网络、端口暴露和远程维护成本。

对于偶发构建,本地 Mac 或短期远程连接仍然更简单;但当任务需要持续在线、完整留存日志,并在主机重启后恢复服务时,具备 root 权限和稳定在线能力的 JEXCLOUD 远程 Mac 更适合作为独立打包环境。最终应根据构建频率选择临时租赁或长期环境,而不是把 SSH 窗口本身当成可靠的任务管理器。

完成断线、用户退出和重启三次验收后,如果现有设备仍无法保持在线、保存完整证据或自动恢复服务,可以查看 JEXCLOUD 的远程 Mac 方案,再决定是否把临时构建升级为常驻 iOS 打包环境。

JEXCLOUD

让远程 Mac 稳定完成每一次构建

使用 JEXCLOUD 远程 Mac 执行 Archive、签名与发布任务,SSH 断开后也能更从容地恢复工作。

按需租用 Mac 资源,无需购买和维护实体设备,适合个人开发者、团队协作与持续集成场景。

立即租用