Kotlin 2.4.10 iOS 构建:2026 远程 Mac CI 怎么部署

这篇文章面向以 Windows 或 Linux 为主力系统的 Kotlin Multiplatform 开发者和移动 DevOps 工程师。你将看到远程 Mac 在 Framework 生成、模拟器测试、Xcode Archive、签名凭据、缓存隔离和重启恢复中的职责边界,并获得一套可复跑的上线验收方法。

Kotlin 2.4.10 iOS 构建:2026 远程 Mac CI 怎么部署

目录

远程构建任务在 Windows 或 Linux 上通过了 Gradle,却卡在 iOS Framework、Simulator 或签名归档阶段。

最快解法:让 Windows 或 Linux 负责共享代码开发和多数 Gradle 检查,把 Kotlin 2.4.10 iOS 构建中的 Framework 集成、模拟器验证、Xcode 测试与最终 Archive 固定路由到安装完整 Xcode 的真实远程 Mac。

谁该看这篇:
如果你主要在 Windows 或 Linux 上开发 Kotlin Multiplatform iOS 项目,需要一个稳定的 Apple 构建出口,这篇文章适合你。
移动 DevOps 工程师、负责共享 Mac 节点的研发平台负责人,也可以用下面的验收条件判断节点是否具备长期承载 CI 的资格。

最后更新于 2026 年 8 月 27 日,版本与构建边界核实自 Kotlin 官方文档、Kotlin 官方版本记录及 Apple Developer 文档。Kotlin 2.4.10 的稳定版本发布日期按官方 release 记录为 2026 年 7 月 14 日;不要把 2.4.20-RC 的行为当作 2.4.10 的稳定能力。

先划清 Windows、Linux 与远程 Mac 的职责

Kotlin Multiplatform 的共享业务代码不需要全部搬到 macOS。你可以在主力系统上完成 commonMain 代码、Android 构建、静态检查、代码格式化和多数 Gradle 任务;但 Apple 目标的最终二进制、Xcode 工程和签名链路必须在真实 Mac 上闭环。

Kotlin 官方明确说明,Windows 和 Linux 不能构建 Apple 目标的最终二进制;如果项目使用 CocoaPods 或其他 cinterop 依赖,Apple 目标的构建限制还会进一步收紧。(kotlinlang.org)

工作内容 Windows/Linux 主力环境 远程 Mac CI 节点 上线前证据
共享 Kotlin 代码、普通单元测试 ✅ 主要承担 可复跑 Gradle 日志、测试报告
Android 产物与静态检查 ✅ 主要承担 不必默认执行 APK、检查结果
iosArm64iosSimulatorArm64 Framework ⚠️ 不能作为最终 Apple 产物出口 ✅ 固定执行 Framework 目录与架构检查
Xcode 工程编译、Simulator 测试 ❌ 不承担 ✅ 固定执行 xcresult、测试日志
Apple 签名、Archive、导出 ❌ 不承担 ✅ 受控执行 .xcarchive、导出包、签名验证
任务恢复与并发隔离 只能发起任务 ✅ 必须验收 断连、重启、复跑记录

边界不要靠“本地能不能打开项目”判断,而要用一次全新克隆验证:清空工作目录,从仓库重新拉取代码,安装声明的依赖后,是否能进入 Apple 构建阶段。如果只能依赖某台开发者电脑上的本地 Framework、手动生成的配置或交互式 Xcode 设置,就还不能称为可交付的 CI。

源码、构建参数、缓存和最终产物也要分开管理。主力系统提交源码与锁定文件,CI 接收提交版本和安全变量;远程 Mac 生成 Framework、测试结果与 Archive;最终产物再上传到制品存储,而不是长期留在工作目录中。

Framework 产物必须覆盖设备与模拟器

Kotlin 2.4.10 iOS 构建不能用单个成功的 iosArm64 任务证明交付完成。iosArm64 面向真实 iPhone 或 iPad 设备,Apple Silicon Mac 上的 iOS Simulator 通常对应 iosSimulatorArm64;两者分别代表不同目标,缺少其中一个,后续测试或集成可能在另一端失败。(kotlinlang.org)

在共享模块的 Gradle 配置中,建议明确声明目标并生成 XCFramework:

kotlin {
    val xcf = XCFramework()

    listOf(
        iosArm64(),
        iosSimulatorArm64()
    ).forEach { target ->
        target.binaries.framework {
            baseName = "SharedKit"
            xcf.add(this)
        }
    }
}

Kotlin 官方文档列出了 assembleXCFrameworkassemble<FrameworkName>DebugXCFrameworkassemble<FrameworkName>ReleaseXCFramework 等任务。实际项目中不要把任务名硬编码成自己的猜测,应先在 CI 上执行任务列表,再选择与你的模块名和构建类型对应的任务。(kotlinlang.org)

产物方式 适合的仓库结构 优点 主要风险
直接集成 Framework Kotlin 与 iOS 工程同仓库 修改共享代码后可直接触发 iOS 构建 Build Phase 与 Gradle 调用关系复杂
本地 CocoaPods iOS 工程已经依赖 CocoaPods,且共享模块同仓库 适合已有 Pod 工作流的团队 Pod 安装、脚本路径和版本锁定容易污染 CI
远程 XCFramework 共享模块与 iOS 应用分仓库或需要版本化交付 依赖边界清楚,可独立发布 需要管理产物存储、版本号和校验
Swift Package 搭载 XCFramework 团队希望以 SwiftPM 方式消费二进制 Xcode 工程依赖更标准 需要额外维护 Package 描述与远程文件

Kotlin 官方建议根据本地依赖、CocoaPods、Swift Package 或远程二进制依赖的实际工程结构选择集成方式,而不是把所有项目都改造成同一种模板。(kotlinlang.org)

每次生成 XCFramework 后,至少保留以下证据:

如果你的仓库包含多个共享模块,优先考虑一个明确的 umbrella module,避免 iOS 工程分别接入大量内部 Framework。Kotlin 官方的多模块示例也采用 umbrella framework 汇总依赖,再生成可供 Xcode 使用的 XCFramework。(kotlinlang.org)

Xcode 集成要围绕仓库结构固定下来

远程 Mac 不是“把本地桌面搬到云端”。它更适合执行确定的工程动作:调用 Gradle 生成 Framework、更新 Xcode 工程依赖、运行固定 Scheme、保存测试结果并创建 Archive。

直接集成时,Xcode Build Phase 中常见一个调用 Gradle 的脚本;CocoaPods 则增加 Pod 安装和脚本生成环节;远程 XCFramework 通常由独立的制品版本提供。三种方式的差异不在名称,而在谁负责生成 Framework、谁锁定版本、谁对失败负责。

你应在仓库中显式固定以下内容:

  1. Xcode 工程或 workspace 的路径;
  2. CI 使用的 Scheme 名称;
  3. Debug、Release 或专用 CI 配置;
  4. Framework 生成任务;
  5. Build Phase 中的脚本入口;
  6. 依赖解析命令与锁定文件;
  7. Team ID、Bundle ID 和签名配置的注入方式。

示例命令统一使用占位符,避免把真实项目路径或凭据写进脚本:

set -euo pipefail

./gradlew :shared:assembleSharedKitReleaseXCFramework

xcodebuild \
  -workspace "<WORKSPACE_PATH>" \
  -scheme "<SCHEME_NAME>" \
  -configuration "<CONFIGURATION>" \
  -destination "generic/platform=iOS" \
  -archivePath "<ARCHIVE_PATH>" \
  archive

全新克隆后,如果脚本仍然引用 /Users/<某位开发者>/Desktop/、本机生成的 Pod 路径或交互式 Xcode 设置,应该先修复工程,而不是给 Runner 增加更多权限。

你可以先在 VPSMAC 的远程 Mac 节点页面确认适合持续构建的访问方式,再决定是短期验证单个仓库,还是建立长期 CI 节点。真正需要比较的是节点是否能稳定执行命令、保存产物并在断连后恢复,而不是远程桌面看起来是否流畅。

测试阶段要拆开 Kotlin、Native 与 Xcode 责任

Kotlin Multiplatform 项目至少有三类测试,不应全部塞进一个“测试失败”步骤里:

模拟器测试不要只检查命令退出码。至少记录:

xcodebuild \
  -workspace "<WORKSPACE_PATH>" \
  -scheme "<SCHEME_NAME>" \
  -destination "platform=iOS Simulator,name=<SIMULATOR_NAME>,OS=<IOS_RUNTIME>" \
  -resultBundlePath "<RESULT_BUNDLE_PATH>" \
  test

Apple 文档说明,Xcode 可以在 Simulator 或连接的真实设备上运行 iOS 应用;Simulator 适合快速迭代,但不能替代真实设备上的最终性能验证。(developer.apple.com)

此外,Apple 提供的 CI 环境变量文档明确包含 .xcresult 结果包路径、测试设备类型、运行时和 UDID 等信息。你应把结果包作为 CI 制品保存,而不是测试完成后直接删除。(developer.apple.com)

验证阶段 主要任务 失败优先定位 退出条件
共享逻辑 commonTest、静态检查 Kotlin 代码与依赖 测试报告完整
Kotlin/Native Apple 目标编译或 Native 测试 Kotlin/Native、cinterop、链接参数 目标任务可复跑
Simulator 安装并运行 iOS 应用 运行时、架构、Simulator 状态 应用启动且测试通过
Xcode Test workspace、Scheme、Framework、资源 Xcode 工程与 Build Phase 生成 .xcresult
真实设备抽查 连接设备或发布前验证 签名、权限、真实系统行为 由团队发布策略决定

远程 Mac 不一定适合交互式图形调试。如果节点主要提供 SSH、Runner 或网页控制台访问,就把图形会话当作故障排查工具,不要把“能打开 Simulator”当作 CI 稳定性的证明。

Archive、签名与发布要做成可观察流水线

自动归档最容易失败的原因,不是 xcodebuild archive 这一行命令本身,而是前置依赖、Framework 版本、Scheme 配置和签名资源没有被明确管理。

建议把 Xcode CI 拆成以下阶段:

阶段 输入 产物 停止条件
依赖解析 锁定文件、Pod 或 SwiftPM 配置 依赖目录、解析日志 依赖版本可记录
Framework 构建 Kotlin 源码、Gradle Wrapper、目标配置 XCFramework 设备与模拟器切片齐全
工程测试 workspace、Scheme、Framework .xcresult 测试通过且结果包可读
Archive Release 配置、签名环境 .xcarchive Archive 存在且包含目标应用
Export Archive、导出选项 IPA 或其他发布产物 导出成功、签名可验证
上传或交付 发布凭据、制品路径 上传记录、校验摘要 失败时可停止并回滚

Apple 的发布工作流文档把构建、签名、归档和分发视为连续但可独立配置的步骤;Apple 的分发文档也要求使用匹配的 App ID、证书和 provisioning profile。(developer.apple.com)

签名凭据必须与日常开发账户隔离。证书私钥、描述文件、App Store Connect 密钥和导出密码不能写入仓库,也不能以明文出现在普通构建日志中。CI 只应通过安全变量、临时钥匙串或受控凭据存储注入,并在任务结束后清理临时文件。

示例命令可以这样保留占位符:

xcodebuild \
  -exportArchive \
  -archivePath "<ARCHIVE_PATH>" \
  -exportOptionsPlist "<EXPORT_OPTIONS_PLIST>" \
  -exportPath "<EXPORT_PATH>"

验收标准不是“有人在 Xcode 中点过 Archive”,而是全新克隆后,无人工点击完成 Framework 生成、Xcode Test、Archive 和导出;随后检查 .xcarchive、应用包、签名身份、Bundle ID 与目标环境是否匹配。Apple 还提醒,分发证书和 provisioning profile 共同决定导出应用的授权范围。(developer.apple.com)

缓存、并发与重启恢复决定节点能否长期使用

Kotlin iOS 构建节点的缓存不能只看“越多越快”。不同缓存的失效条件不同,错误复用会把旧 Framework、旧 Derived Data 或不匹配的依赖带进新任务。

建议分开观察:

缓存命中后仍然失败,先执行一次隔离复跑,再决定是否清理。不要把“清空全部缓存”当成默认修复方案,否则你无法判断真正的问题来自缓存污染、依赖变更还是工程配置。

共享 Runner 还需要避免三类争用:

  1. 两个任务使用同一个工作目录;
  2. 两个任务同时操作同一个 Simulator;
  3. 两个项目共用未经隔离的签名钥匙串或临时导出目录。

如果使用 GitHub Actions,可以通过自托管 Runner 标签把 iOS 任务路由到指定的 macOS 节点,例如为 Runner 配置 self-hostedmacOSarm64 和项目专用标签。GitHub 官方文档说明,标签可用于按 Runner 特征选择执行节点,标签名称不区分大小写。(docs.github.com)

jobs:
  ios:
    runs-on:
      - self-hosted
      - macOS
      - arm64
      - ios-kmp

节点上线前,至少完成下面 5 步恢复测试:

  1. 通过 SSH 或 Runner 执行一次全新克隆构建;
  2. 构建中途断开 SSH,确认 CI 任务不会依赖交互式终端;
  3. 重启远程 Mac,检查 Runner 是否能自动恢复;
  4. 使用新的工作目录重新调度同一提交;
  5. 连续执行两个不同项目,确认工作目录、Simulator 和签名资源互不污染。

评分可以这样执行:

总分 8 分及以上,才适合把节点纳入持续 CI;低于 8 分,先修复恢复与隔离问题,不要急着接入正式发布分支。这里的分值是本文的验收模型,不代表 Kotlin 或 Apple 的官方评级。

常见问题

没有本地 Mac 时,Kotlin Multiplatform iOS 应用还能完成构建吗?

可以完成共享代码开发和部分 Gradle 检查,但不能把 Apple 最终交付完全留在 Windows 或 Linux 上。你需要将 Framework、Simulator、Xcode Test、签名和 Archive 路由到真实 macOS 节点,并通过全新克隆证明流程不依赖本地开发机。

哪些 Kotlin Multiplatform iOS 工作必须放到 macOS?

生成 Apple 最终二进制、执行 cinterop、链接 Apple SDK、启动 iOS Simulator、运行 Xcode 测试、创建 Archive 和使用签名凭据,都应放到 macOS。普通共享逻辑测试可以继续留在主力系统,以减少远程节点负担。

远程 Mac 上生成 Kotlin XCFramework 后,应该怎样验收?

同时声明 iosArm64iosSimulatorArm64,执行对应的 Release XCFramework 任务,并检查产物目录、架构切片、模块导入和重复生成结果。只生成单一设备 Framework,不能证明模拟器和最终 Xcode 工程都可用。

Kotlin Multiplatform iOS 工程接入 CI 自动归档时,流程如何拆分?

先固定 workspace、Scheme、构建配置和 Gradle 任务,再按依赖解析、Framework、测试、Archive、Export 分阶段执行。签名资源通过安全凭据注入,Archive 与导出文件必须保存为 CI 制品,并对失败阶段设置明确停止条件。

Kotlin iOS 构建节点应保留哪些 Gradle 与 Xcode 缓存?

重点是 Gradle 依赖、Kotlin/Native 编译缓存、Derived Data、CocoaPods 或 SwiftPM 依赖和必要的 Simulator runtime。缓存要按项目与版本隔离,并保留命中日志;证书、私钥和临时钥匙串不能作为普通共享缓存。

对你现在的方案来说,Windows 或 Linux 继续作为主力开发机通常是合理的,但它们无法独立完成 Apple 最终二进制、Simulator 验证和 Xcode 签名归档;临时虚拟 macOS 或手动桌面转发又常常带来架构不匹配、图形会话不稳定、凭据难隔离和节点重启后无法自动恢复等问题。相比之下,先通过 VPSMAC 的远程 Mac 方案租用一台可通过 SSH 或远程控制方式访问的真实 Mac,把全新克隆、XCFramework、Xcode Test、Archive 和恢复流程跑通,再决定是否长期承载 CI,通常更适合需要临时构建出口或正在验证团队流程的开发者。若你的项目已经确定要长期承载高并发发布任务,仍应进一步评估独占硬件、物理设备接入和签名治理,而不是把租赁节点无条件当作永久替代方案。

常见问题

没有本地 Mac,Kotlin Multiplatform iOS 应用还能完成构建吗?

可以,但不能把完整 iOS 交付链路留在 Windows 或 Linux 上。共享代码、普通 Gradle 检查和部分业务开发可以在主力系统完成;最终 iOS Framework、Apple 目标二进制、模拟器运行、Xcode 测试、签名和 Archive 应交给安装完整 Xcode 的真实 Mac 节点。

Kotlin Multiplatform 哪些 iOS 任务必须放到 macOS?

只要任务需要生成 Apple 最终二进制、调用 Xcode 工具链、链接 Apple SDK、启动 iOS Simulator、执行 Xcode 测试或使用签名证书,就应放在 macOS。Kotlin 官方说明,Windows 和 Linux 不能构建 Apple 最终目标;涉及 CocoaPods 或 cinterop 时,macOS 限制也更严格。

远程 Mac 怎样生成并验证 Kotlin XCFramework?

在远程 Mac 上同时声明 iosArm64 与 iosSimulatorArm64,执行对应的 assemble XCFramework 任务。验收不能只看任务退出码,还要检查 XCFramework 是否包含设备与模拟器切片、Xcode 能否导入模块、修改共享代码后是否生成新产物,并保存目录清单和校验记录。

Kotlin Multiplatform iOS 项目如何接入 CI 自动归档?

把流程拆成依赖解析、共享模块构建、Framework 集成、Xcode test、Archive 和 export 几个阶段,并让 CI 使用固定 Scheme、配置文件和工作目录。签名证书与描述文件通过安全凭据注入,最终以无人工点击完成 Archive、校验导出文件和失败回滚作为验收标准。

Kotlin iOS 构建节点应该缓存哪些 Gradle 和 Xcode 文件?

优先区分 Gradle 依赖缓存、Kotlin/Native 编译缓存、Xcode Derived Data、Simulator runtime 和 CocoaPods 或 Swift Package 依赖。缓存命中必须有日志证据;工作目录、模拟器状态和签名资源不能在并发任务之间共享,否则一次失败可能污染后续构建。

延伸阅读