给负责合并与发布的人

把下一次合并,交给专属构建节点

先手动产出一份可验证的 ipa,再把任务交给 CI。这里按开机、连接、接入、分发与日常维护组织步骤,不要求你先重写现有流水线。

以一小时试接为目标,而非交付时限承诺;大型依赖下载、Xcode 安装和签名材料准备会影响耗时。已有节点可直接从连接检查开始。

开机前,先收齐输入

先开一台能承接当前项目的节点

如果只是偶尔打包且已有闲置 Mac,继续自建可能更省;如果每天多次合并、不想值守电源、网络与散热,再考虑独享托管。OSXPort 提供整台物理 Mac mini,一个节点只交给一个客户,不是虚拟机。

  1. 01

    确认工程基线

    准备一条可复现的构建命令、代码访问方式、Xcode 版本要求与依赖锁文件。先选一个 App、一个 scheme 和一条分支,不要把首次接入变成整套发布系统迁移。

  2. 02

    选择配置与周期

    在下单页选择机型、区域与按天/周/月/季周期。Port M4 Base 适合轻量试跑;多分支构建和模拟器任务优先评估 Port M4 Plus;大型多 target 工程再评估 Port M4 Pro。

  3. 03

    保存交付信息

    完成订单后,在控制台查看节点地址、连接用户名及凭据。实际可用状态以控制台实时返回为准。把节点标识写进团队资产登记,不要把登录密码写进仓库或工单正文。

  4. 04

    确定就近区域

    可选新加坡、日本(东京)、韩国(首尔)、香港、美国西部。除团队位置,还要考虑仓库和依赖源的位置;跨区域网络的实际表现需要用自己的拉取与上传任务验证。

三个档位分别为 Apple Silicon M4 · 16GB 统一内存 · 256GB SSD、Apple Silicon M4 · 24GB 统一内存 · 512GB SSD,以及 Apple Silicon M4 Pro · 64GB 统一内存 · 2TB SSD。首次试接不建议直接堆高并发,先记录单次构建的内存、磁盘与产物大小。

先验证机器,再接流水线

让同一用户完成登录、编译与导出

第一次连接先核对节点地址和用户,再检查开发工具。下面是示例会话,不是实时节点输出;版本号仅用于展示格式,实际以当前节点执行结果为准。

按三层检查,不急着重装环境

连接层:先用控制台交付的地址、端口和用户名连接。首次连接应核对主机指纹;意外变化时先确认节点是否更换,不要直接跳过校验。出现超时先查地址与网络,出现拒绝认证再查用户和凭据。

工具层:用 xcode-select -p 确认当前开发者目录,用 xcodebuild -version 记录版本。如果项目要求另一版本,先确认该版本已安装,再显式切换路径。

工程层:在项目目录安装锁定的依赖,先手动运行既有构建命令。交互登录成功不等于后台 runner 能访问签名材料;后续必须用 runner 的实际执行用户再验证一次。

示例中的 NODE_USER 与 NODE_ADDRESS 需设置为控制台交付值;App.ipa 是示例产物名。若项目通过 Bundler 管理 fastlane,请使用项目约定的 bundle exec fastlane gym。

osxport · tokyo-node
$ ssh "$NODE_USER@$NODE_ADDRESS"
$ xcode-select -p
/Applications/Xcode.app/Contents/Developer
$ xcodebuild -version
Xcode 16.4
Build version 16F6
$ cd ~/workspace/App
$ fastlane gym
Creating archive
Exporting archive
Successfully exported and compressed dSYM file
Successfully exported and signed the ipa file
Exported ipa: ./build/App.ipa
$ ls -lh ./build/App.ipa

验收点:远程命令退出成功、版本符合工程要求、产物路径存在。签名或编译失败时保留首次报错前后的日志,不要只截最后一行。

沿用团队已有的 CI

注册执行器之前,先跑通一条手动任务

三种接法都在同一台 macOS 物理节点上执行。下面的人数是组织方式建议,不是容量承诺;应按单次构建内存、同时运行的模拟器数量和磁盘占用确定并发。

GitHub Actions 自托管 runner

适合:约 3~15 人、已经通过工作流文件协作的团队。无需另建调度系统,将节点登记到受控仓库或组织即可。

  1. 从仓库或组织设置获取适用于当前 macOS 与芯片架构的 runner 安装包和注册指令。
  2. 使用专用执行用户完成注册,添加团队自定标签,并把工作流的 runs-on 指向该标签。
  3. 先跑版本检查和无敏感信息的构建任务,再配置后台服务、密钥注入与产物上传。

不建议:把包含签名材料的节点开放给不受信任的外部合并请求。主机独享不等于每个工作流相互隔离。

检查执行器验收项

GitLab Runner · shell executor

适合:约 3~30 人、代码和权限管理已集中在 GitLab 的团队。shell executor 直接使用节点上的 Xcode 与命令行环境。

  1. 安装适用于 macOS 的 GitLab Runner,使用项目或群组提供的注册信息登记执行器。
  2. 选择 shell executor,设定专用标签,并限制可运行的受保护分支与任务范围。
  3. 把依赖恢复、编译、导出与产物保存写成可独立验证的阶段,先从单任务并发开始。

不建议:在同一 shell 执行器上混跑互不信任的客户仓库;工作目录和宿主机权限需要你主动治理。

检查执行器验收项

Jenkins agent

适合:约 10~30 人、已有 Jenkins 控制器和发布审批流程的团队。节点作为 macOS agent 加入,不必迁移整套流水线。

  1. 在控制器创建独立 agent,指定节点标签、专用工作目录与执行用户。
  2. 按控制器配置建立连接,确认所需 Java 版本和 agent 运行环境兼容,再启用常驻运行。
  3. 让测试任务显式选中 macOS 标签,检查环境变量、工具路径和产物归档权限。

不建议:只为偶尔一次打包新建控制器。已有轻量 CI 时,增加维护对象通常没有必要。

检查执行器验收项

执行器显示在线,还需要过这四项

使用 runner 的实际执行用户验证,而不是只在个人交互会话里验证。
检查项验证方式通过条件
工作目录与工具执行 whoami、pwd 与 xcodebuild -version用户、目录和 Xcode 版本均符合任务配置
仓库与依赖访问用 CI 注入的受限凭据拉取指定分支,并按锁文件恢复依赖不依赖个人终端中未声明的令牌或路径
签名可用性在非交互任务中完成归档与导出没有等待人工确认的弹窗,凭据不写入日志
重连与产物保存检查后台服务状态,并在任务完成后取回产物及日志执行器可恢复连接,产物不只留在临时工作目录

同一个节点可以注册多个受控任务入口,但它们仍共享 CPU、统一内存和 SSD。先限制并发为一个构建,再依据自己的测量逐步增加;多个 runner 名称不会增加物理资源。

Windows 写代码,macOS 做打包

把 Flutter 的 iOS 阶段留在远端执行

Windows 可以承担编码、提交与查看日志;iOS 编译和签名仍在云端 Mac 上运行。独享节点不会省去有效的 Apple 开发者计划资格、签名证书、私钥和与应用匹配的描述文件。

  1. 01

    固定依赖

    同步同一提交和锁文件,确认 Flutter、Dart、CocoaPods 与 Xcode 的兼容关系。先执行 flutter doctor -v 检查工具链,再执行 flutter pub get;不要把另一台电脑的绝对路径带进工程。

  2. 02

    导入签名材料

    通过团队批准的安全方式传递证书、私钥与描述文件。在实际构建用户可访问的专用钥匙串中导入证书,配置描述文件与导出选项;检查 bundle identifier、团队标识与目标分发类型是否一致。

  3. 03

    执行并取回

    运行 flutter build ipa --release;项目需要指定导出规则时传入对应的 --export-options-plist。产物通常位于工程的 build/ios/ipa/,以实际输出为准,再由 CI 归档回团队的产物存储。

  4. 04

    分清测试边界

    远端可执行模拟器测试和自动化构建;涉及本地实物设备、传感器与交互体验的验证仍应保留在设备侧。React Native 团队同样可把 iOS 编译阶段放在节点上,但要按工程自己的脚本恢复依赖。

缓存是提速手段,不是备份。按工程、Xcode 版本和依赖锁文件设计缓存键;签名异常先检查有效期、私钥与描述文件匹配关系,不要先删除所有构建缓存。

先证明能导出,再配置上传

让分发凭据与节点登录凭据分开管理

TestFlight 分发需要应用已在 App Store Connect 中完成必要配置,并具备相应发布权限。API Key 用于授权上传,不替代编译时需要的签名证书与描述文件。

配置顺序

  1. 确认可安装的产物。先用 fastlane gym 或工程既有命令完成归档与导出,确认 bundle identifier、版本号和构建号。
  2. 准备 API Key。由有权限的负责人创建适当角色的 App Store Connect API Key,记录 Key ID、Issuer ID,并安全保管私钥文件。
  3. 注入到 CI。把私钥和标识放入团队的密钥管理中,任务开始时生成受限配置文件,任务结束后移除。不要把配置或私钥提交到仓库。
  4. 上传并确认处理状态。执行 pilot,核对应用标识与上传结果。上传成功不表示已向测试人员开放,后续处理和测试分发仍需确认。

已有 ipa 时的上传命令

fastlane pilot upload \
  --api_key_path "$ASC_API_KEY_JSON" \
  --ipa "$IPA_PATH" \
  --skip_waiting_for_build_processing true

ASC_API_KEY_JSON 指向按 fastlane 格式生成的临时 API Key 配置,IPA_PATH 指向实际 ipa。若使用 Bundler,在命令前加 bundle exec。

保留应用版本、构建号、提交标识和上传结果;不要把私钥内容或完整认证配置打印到日志。

上传失败时,按错误类型排查

认证错误先核对 Key ID、Issuer ID、私钥与角色权限;重复构建号先调整构建号,不必重新配置 runner;签名或应用标识错误则回到归档与导出阶段。把编译、签名、上传拆成三个验收点,能避免每次都从头重跑整条任务。

把交接写进流水线

节点全年在线,任务仍要能够迁移

节点全年 365 天在线运行,没有计划停机。机房承担电源、网络与散热;你的团队负责工程依赖、密钥、任务配置与数据备份。硬件异常需要通过工单核查,不把单节点当作不可丢失的唯一副本。

平时保留可重建清单

把 runner 标签、工具版本、环境变量名称、依赖安装流程和签名导入步骤记录下来。使用自动化脚本重建环境,比依赖个人记忆更容易交接。

签名证书及私钥应加密备份;构建产物和日志应取回团队存储。DerivedData、依赖缓存可按成本决定是否备份,但必须允许重新生成。

回看接入验收清单

异常时先保留证据

记录节点标识、发生时间与时区、最后一次成功任务及错误摘要。分别说明 SSH 是否可连、runner 是否在线、任务是否能开始,避免只写“打包坏了”。

若还能登录,先导出必要数据和日志,再暂停新任务。工单中只放脱敏信息;需要授权排障时,明确授权范围,不发送私钥或完整密码。

登录控制台报告异常

确认换机后重新验收

支持人员核查异常后,通过工单确认处理方式;需要更换节点时,按交付信息更新地址和凭据,并重新核对主机指纹。

恢复依赖和签名材料、重新注册或关联 runner,再跑一条最小构建。确认新节点可接任务后,撤销旧连接凭据和不再使用的 runner 注册。

按连接步骤重新检查

日常磁盘清理应先确定保留策略:产物按发布版本保存,日志按团队审计要求保存,缓存按可重建原则轮转。不要在构建进行中清理工作目录或切换全局 Xcode 路径。

让账单和节点一起交接

发布前检查有效期,不靠最后一封提醒

按天适合首次试跑或短期构建任务;按周适合阶段性集中工作;按月、按季更适合常驻 nightly。周期选择应对照实际目录总价,不要把按天单价直接当成长期预算。

调整环境前,先确认边界

团队接管节点时常问的六件事

能安装 Homebrew 和项目自己的依赖吗?

可按常规 macOS 工程方式管理开发工具与项目依赖。安装前检查架构、安装路径和权限要求;将版本与安装步骤纳入环境登记。首次接入优先复现项目已有依赖,不要同时升级所有工具,否则很难判断失败来自工程还是环境变化。

可以自选 Xcode 版本吗?

按工程兼容要求选择版本,并先在节点确认已安装内容。需要安装其他版本时,先核对磁盘空间、获取方式与项目要求;不要默认某个版本一定预装。多任务共用节点时,优先在任务环境中设置 DEVELOPER_DIR,避免全局切换影响正在执行的其他任务。

有 root 权限吗,runner 需要用 root 跑吗?

macOS 图形界面与命令行完整可用。具体管理员身份和可用的 sudo 权限应按控制台交付凭据确认;若安装步骤需要额外授权,先提交工单核实。不要把 root 直登当作默认连接方式,也不建议用高权限用户执行普通 CI 任务。构建、密钥和工作目录应按最小权限分开管理。

同一个团队能让多人使用一台节点吗?

可以把同一独享节点纳入团队工作流,但整台机器的物理资源不会随用户数增加。分配独立用户或明确的任务入口,限制并发,并约定环境变更时间。不同成员的构建和签名权限需要团队自行管理;不应把它当成彼此隔离的多租户环境。

缓存会不会被别的客户清掉?

整机只交给一个客户,不与其他客户共用构建资源。缓存仍可能被团队自己的清理脚本、磁盘治理或环境变更影响。把它当作可重建加速层,代码、签名材料与最终产物另做备份;换机时也应允许从依赖锁文件恢复。

接入卡住时,工单里应该附什么?

提供节点标识、CI 类型、任务对应的提交标识、发生时间与时区,以及第一处失败附近的脱敏日志。说明同一命令在交互终端和 runner 中是否表现一致。删除访问令牌、私钥、密码和敏感路径中的业务信息;支持人员需要进一步排查时,会通过工单与你确认授权范围。

用一条真实任务,验收这台构建机

先按天试跑,再决定是否长期接管 nightly。Port M4 Base 从 $19.7/天起;保留提交标识、构建日志和产物,让选型依据来自你自己的工程。