SwiftPM 私有依赖:2026 年远程 Mac 配置指南

获胜方案是:在远程 Mac 上为实际执行构建的 macOS 用户配置专用仓库凭据,提交并固定 Package.resolved,再按“依赖解析 → 编译 → Archive”顺序验收。只要构建由 SSH、定时任务或后台服务触发,就不能把个人 Xcode 图形界面的登录状态当成 CI 配置。
这篇文章适合从本地 Mac 迁移到远程构建环境、项目包含私有 Swift 包的独立开发者。
如果项目使用命令行构建、定时打包,或由小团队维护多个私有仓库,重点应放在凭据隔离、权限范围和重启后的可恢复性。
迁移基线:先区分依赖与权限
“Xcode 图形界面能构建,但同一台远程 Mac 的后台任务无法拉取私有包”,是这类迁移中最容易遇到的失败案例。
本地 Xcode 可能已经保存了账户状态、SSH agent 或钥匙串凭据。图形界面因此可以完成依赖解析。但后台任务使用的可能是另一个 macOS 用户、另一个工作目录,甚至是没有交互式会话的进程。它看不到开发者账户里的凭据,构建就会在 SwiftPM 解析阶段停止。
迁移前先建立一份依赖清单:
- 项目直接引用了哪些私有 Swift 包。
- 每个私有包实际对应哪个 Git 仓库。
- 是否存在传递依赖,也就是私有包继续依赖其他私有仓库。
- 当前成功构建使用的提交版本、分支或标签。
- 读取仓库所需的最低权限,而不是开发者个人账户拥有的全部权限。
Apple 的持续集成说明要求将 Package.resolved 提交到代码仓库;如果依赖需要认证,则必须向构建环境提供相应凭据。Apple 关于 Swift 包持续集成的官方说明
建议把权限拆成两类:
- 仓库读取凭据:只允许拉取私有 Swift 包。
- 发布凭据:用于代码签名、上传或发布,不应自动拥有私有仓库读取权限。
这样做可以缩小凭据泄露后的影响范围。私有包密钥被撤销时,不应同时导致签名证书和上架流程失效。
构建用户:SSH 配置必须跟着任务走
远程 Mac 上最关键的身份不是登录 VNC 的账号,而是执行 xcodebuild 或后台任务的 macOS 用户。
例如,开发者通过 VNC 登录的是 developer,但定时任务由 builder 执行。即使 developer 的 ~/.ssh/config 配置完全正确,builder 仍可能无法读取私有仓库。Apple 的 CI 文档要求将 known_hosts 放在执行任务的 macOS 用户的 ~/.ssh 目录中,命令行构建也应遵循该用户的 SSH 配置。Apple 关于私有依赖认证与 SSH 配置的说明
私有仓库认证
私有包的 Git URL 应采用基于 SSH 的形式。项目文件中不应出现私钥、密码或临时访问令牌。
远程 Mac 上先切换到实际构建用户,再准备 SSH 目录:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/config
chmod 600 ~/.ssh/config
随后在 ~/.ssh/config 中为私有仓库主机指定专用密钥。示例只展示结构,不包含真实密钥:
Host private-code-host
HostName code-host.example
User git
IdentityFile ~/.ssh/id_ed25519_swiftpm
IdentitiesOnly yes
这里的 IdentityFile 只是示例路径。实际路径应与构建用户生成的密钥一致。SSH 私钥应只保存在远程 Mac 的构建用户目录,公钥则添加到仓库端的只读授权位置。
代码托管平台的官方文档建议使用 SSH 密钥完成 Git 操作,并通过 ssh-agent 管理带口令的私钥。官方 SSH 密钥生成与 agent 配置说明
主机校验与最小验证
不要为了绕过错误而长期关闭主机校验。正确做法是先确认仓库主机的指纹,再把可信主机写入对应构建用户的 known_hosts。
可以先执行:
ssh -T git@private-code-host
如果代码托管平台使用不同的 SSH 用户名或主机名,应按平台提供的 SSH URL 调整命令。SSH 身份验证成功,也不代表目标私有仓库已经授予读取权限。之后还应使用目标仓库执行只读验证,例如:
git ls-remote git@private-code-host:team/private-package.git
官方测试说明也区分了 SSH 身份验证和仓库访问权限,这两个环节必须分别验证。官方 SSH 连接测试说明
⚠️ 经验提醒:如果 VNC 中能拉包、SSH 登录后却失败,先执行
whoami、echo $HOME和ssh -vT,不要先删除缓存。多数情况下,问题是构建用户、HOME 目录或 SSH agent 不一致。
依赖解析:先锁定 Package.resolved
锁定文件的位置与作用
对于持续集成,Package.resolved 应提交到项目仓库,并随依赖升级一起审查。它记录了解析后的依赖版本,可以避免远程环境在每次构建时重新选择版本。Apple 关于 Swift 包依赖的官方文档
Xcode 项目常见的文件路径为:
App.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
工作区项目还应核对实际 .xcworkspace 或 .xcodeproj 结构,不能只凭文件名搜索后随意复制。迁移时常见的错误包括:
Package.resolved没有提交。- 文件被
.gitignore忽略。 - 文件放在错误的项目或工作区目录。
- 本地更新依赖后没有提交新的锁定结果。
- 远程构建目录残留旧缓存,掩盖了文件位置错误。
在运行完整编译前,先使用同一个构建用户和工作目录单独解析:
cd /path/to/project
xcodebuild -resolvePackageDependencies \
-project App.xcodeproj \
-scheme App \
-disableAutomaticPackageResolution
-disableAutomaticPackageResolution 用于要求命令行构建使用 Package.resolved 中的依赖版本,而不是在 CI 中自动重新解析。Apple 关于 CI 中依赖解析的官方命令说明
解析失败的停止点
第一次解析不要和完整编译绑定在一起。这样可以把问题分成三类:
- 认证错误:私钥未加载、仓库公钥未授权,或使用了错误的构建用户。
- 主机校验错误:
known_hosts缺失、主机名不匹配或指纹未确认。 - 版本解析错误:
Package.resolved缺失、路径错误、锁定版本已被删除或权限不足。
只有在依赖目录、解析输出和锁定文件都符合预期后,才进入编译。若解析失败,应在此处停止,不要用清空全部缓存、关闭主机校验或切换个人账户来“修复”问题。
命令行构建:从解析到 Archive 分层验收
命令行无法拉取私有依赖,通常不是 Xcode 本身不能处理 SwiftPM,而是命令行环境没有继承图形界面的凭据。
排查顺序应保持固定:
whoami:确认实际执行用户。echo $HOME:确认 SSH 配置读取位置。git ls-remote:确认专用 SSH 密钥能否读取目标仓库。xcodebuild -resolvePackageDependencies:确认 SwiftPM 能否完成解析。- 再执行编译与归档:确认依赖不只是“能拉取”,还能参与目标构建。
如果项目依赖系统 Git 的 URL 映射、代理或高级 SSH 配置,可评估:
-scmProvider system
Apple 文档将 URL remapping、代理和高级 SSH 配置列为需要系统 Git 工具的典型场景。Apple 关于 xcodebuild 源代码管理选项的说明
首次归档验收
归档命令应尽量贴近后续无人值守任务。不要先在 Xcode 图形界面中点击 Archive 成功,就认为后台任务已经配置完成。
示例:
xcodebuild archive \
-project App.xcodeproj \
-scheme App \
-configuration Release \
-archivePath "$PWD/build/App.xcarchive" \
-disableAutomaticPackageResolution \
| tee build/archive.log
路径和 scheme 需要替换为项目实际值。xcodebuild 支持从命令行执行构建、测试和 Archive;分发流程通常先生成 Archive,再执行导出步骤。Apple 官方命令行构建说明
归档验收至少看三项:
- 私有包解析:日志中没有认证、主机校验或版本漂移错误。
- 目标编译:私有包产品能够被目标正确链接。
- Archive 结果:生成预期的
.xcarchive,并保留对应日志。
失败日志要保留在构建产物目录中。不要只截取终端最后一行,因为 SwiftPM 的真正错误往往出现在前面的 Git 或解析阶段。Apple 对归档和后续导出的流程也有单独说明,可用来核对项目的签名与分发步骤。Apple 官方归档与导出说明
无人值守:让凭据在没有图形会话时仍可用
无人值守构建的关键,不是把所有凭据都放进环境变量,而是让任务在没有 VNC 会话、没有人工输入、SSH 连接已经断开的条件下仍能明确成功或失败。
接入后台任务时,建议按下面的顺序执行:
- 让定时任务使用固定的 macOS 构建用户。
- 将 SSH 配置、专用私钥和
known_hosts放在该用户目录。 - 在任务开始时检查
HOME、SSH 配置路径和密钥文件权限。 - 单独执行私有仓库读取测试。
- 再执行
xcodebuild -resolvePackageDependencies。 - 解析成功后执行编译、测试和 Archive。
- 保存日志、归档路径和失败退出码。
带口令的 SSH 密钥需要由 ssh-agent 或钥匙串在非交互任务中提供。官方文档说明,SSH agent 可以缓存密钥口令;如果密钥不在默认路径,则需要显式告诉 agent 私钥位置。官方 SSH 口令与 agent 说明
但钥匙串并不等于无限授权。构建用户仍应只拥有构建所需的仓库读取权限,代码签名凭据则放在单独的 Keychain 管理流程中。私有包密钥轮换时,不应顺带影响 App Store 发布权限。
如果团队不熟悉远程 Mac 的账号、SSH 和后台任务管理,可以先参考 ProxyMac 帮助中心,确认远程连接、用户权限和主机重启后的登录方式,再进入项目级配置。
冷启动复验:重启后重新证明可用
重启后密钥失效,不能直接判断为私钥损坏。应依次检查:
- 构建任务是否仍由原来的 macOS 用户执行。
HOME是否指向原用户目录。- 私钥文件是否仍存在,权限是否合适。
ssh-agent是否重新启动。- 钥匙串是否允许后台任务读取密钥口令。
known_hosts是否仍在构建用户的~/.ssh目录。- 仓库端公钥是否被撤销或过期。
如果私钥由 agent 管理,重启后通常需要重新加载,或者配置可靠的钥匙串恢复方式。不要把私钥直接写进构建脚本,也不要把口令写进项目配置和命令行历史。
完整复验应从干净工作目录开始:
git clean -xfd
git checkout -- .
xcodebuild -resolvePackageDependencies \
-project App.xcodeproj \
-scheme App \
-disableAutomaticPackageResolution
xcodebuild archive \
-project App.xcodeproj \
-scheme App \
-archivePath "$PWD/build/App.xcarchive" \
-disableAutomaticPackageResolution
是否可以使用 git clean -xfd,取决于项目是否把本地配置或生成文件放在仓库目录中。若不确定,先复制工作目录,再执行清理。重点不是强行删除所有文件,而是证明构建不依赖未记录的缓存。
决策条件:什么时候接入长期任务
下面这份条件清单可用于决定远程 Mac 是否已经达到长期运行标准:
- ✅ 构建用户能够独立执行
git ls-remote,且只读访问目标私有仓库。 - ✅
Package.resolved已提交,路径与项目或工作区结构一致。 - ✅ 禁止自动解析时,远程环境仍能完成依赖解析。
- ✅ 没有 VNC 会话时,SSH agent 或钥匙串仍能提供必要凭据。
- ✅ 编译和 Archive 使用的用户、目录、环境变量与定时任务一致。
- ✅ 重启后可以恢复 SSH 配置、主机校验和密钥加载。
- ✅ 私有包读取凭据与代码签名、发布凭据彼此隔离。
- ❌ 只要仍需手动打开 Xcode、点击登录或临时接受主机指纹,就不要接入长期无人值守任务。
- ❌ 只要依赖解析依靠缓存、未提交的锁定文件或开发者个人目录,就不要把当前结果视为可复现构建。
私有包升级时,先在受控环境中更新依赖,再审查 Package.resolved 的变更。审查内容包括私有包版本、传递依赖、仓库权限、二进制包校验以及归档日志。
密钥轮换时,先添加新公钥,再验证远程解析,最后撤销旧公钥。构建用户变更、仓库移除和 Xcode 更新也应重新执行解析、编译、Archive 与重启复验。
如果当前方案是让个人 Mac 长期开机,常见缺点是硬件被单一任务占用、重启后无人恢复、开发者个人凭据与构建凭据混用;如果改用临时云主机,又可能遇到无法运行 macOS 工具链、SSH 凭据迁移复杂和环境生命周期不稳定的问题。对于需要先验证私有依赖冷启动、再逐步接入无人值守任务的团队,ProxyMac 的远程 Mac 更适合作为短周期测试环境或持续在线的构建节点;先用真实项目完成解析、归档和重启复验,再决定是否延长租赁周期,通常比直接购买一台专用 Mac 更容易控制试错成本。
如果构建在无图形会话下仍能读取私有包、使用固定的 Package.resolved 完成 Archive,并且重启后流程可以恢复,才说明这台远程 Mac 真正具备接入长期自动打包任务的条件。需要临时算力、迁移验证环境或常驻 iOS 打包服务器时,可查看 ProxyMac 的远程 Mac 方案,再按项目运行时长、凭据隔离要求和是否需要物理接口做选择。