远程 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 来说,真正有价值的证据至少包括标准输出、错误输出、退出状态、xcresult 或 xcarchive,以及最终导出目录。
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 的文档将 archive 和 exportArchive 明确作为不同动作;官方示例也使用 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 | xcarchive、ExportOptions.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
- 启动一个不会上传到生产环境的测试 Archive。
- 确认日志文件已经开始写入,并记录任务 ID。
- 主动关闭本地 SSH 连接,不关闭远程任务会话。
- 等待任务自然结束后重新登录。
- 检查进程状态、完整日志、退出码、
xcarchive和日志结束标记。
第二次:任务运行时退出用户会话
- 使用与正式构建相同的账号启动测试。
- 退出图形用户会话,或者切换到另一个用户。
- 分别测试纯命令行 Archive、Simulator 测试和签名任务。
- 对比哪些任务继续、哪些任务阻塞、哪些任务因 Keychain 或图形上下文失败。
- 恢复原登录状态,并记录回退方法。
第三次:主机重启后验收服务
- 先保存当前 Runner 或后台作业配置。
- 重启远程 Mac,确认服务是否由
launchd重新加载。 - 检查 Xcode 开发者目录、工作目录、环境变量和日志权限。
- 提交一个不会上传的测试构建。
- 验证服务状态、任务状态、退出码和产物是否可查询。
如果采用 Runner,重点不是只看服务是否显示“运行中”,还要确认它能接收任务、启动正确账号,并在任务失败后留下日志。Apple 的 launchd 文档可以帮助确认作业文件位置、启动参数和保持运行策略,但具体构建是否适合无人值守,仍必须通过上述验收验证。
07 断线恢复检查清单
- [ ] 已为每次构建生成唯一的
<JOB_ID>,并使用独立日志目录。 - [ ] 标准输出与错误输出没有只保存在 SSH 终端窗口中。
- [ ] Archive、导出、上传分别拥有独立的退出码和完成标记。
- [ ] 已记录
xcarchive、xcresult、导出目录和交付记录的位置。 - [ ] 断开 SSH 后,能重新定位任务会话或后台作业。
- [ ] 重连时会先检查原任务,而不是立即重复执行整条流水线。
- [ ] 已测试用户退出后,Keychain、Simulator 和签名任务的实际表现。
- [ ] 已测试主机重启后服务是否自动加载。
- [ ] 终止进程、修改权限或注册作业前,已有影响范围和回退记录。
- [ ] 真实发布前,已经用测试构建验证过版本号和构建号不会重复。
如果你的项目还处于一次性手动构建阶段,可以先参考 远程 Mac 的基础使用入口,把可重连会话和日志留存做好;当夜间测试或多人提交开始增加,再把任务迁移到常驻 Runner。需要长期在线环境时,可进一步对照 远程 Mac 租赁方案 的周期和使用方式,而不是继续依赖个人电脑临时开机。
08 当前设备与远程 Mac 方案的取舍
如果当前方案是个人 Windows / Linux 电脑加临时 SSH 连接,常见缺点有 3 个:电脑关机后无法接收任务;前台 Shell 断线后容易丢失日志;没有固定的服务账号和重启验收流程时,夜间构建很难确认是否真的完成。把 Mac 临时放在办公室或家里也会增加电源、网络、端口暴露和远程维护成本。
对于偶发构建,本地 Mac 或短期远程连接仍然更简单;但当任务需要持续在线、完整留存日志,并在主机重启后恢复服务时,具备 root 权限和稳定在线能力的 JEXCLOUD 远程 Mac 更适合作为独立打包环境。最终应根据构建频率选择临时租赁或长期环境,而不是把 SSH 窗口本身当成可靠的任务管理器。
完成断线、用户退出和重启三次验收后,如果现有设备仍无法保持在线、保存完整证据或自动恢复服务,可以查看 JEXCLOUD 的远程 Mac 方案,再决定是否把临时构建升级为常驻 iOS 打包环境。
让远程 Mac 稳定完成每一次构建
使用 JEXCLOUD 远程 Mac 执行 Archive、签名与发布任务,SSH 断开后也能更从容地恢复工作。
按需租用 Mac 资源,无需购买和维护实体设备,适合个人开发者、团队协作与持续集成场景。
立即租用