关于 limrun-xcode
limrun-xcode 是用于在 Limrun 远程 Xcode 环境构建 Apple 项目的技能,面向需要从不同操作系统或容器进行构建和测试的开发者。它通过 lim 同步源码并运行构建,也可选择 Xcode 版本、复用磁盘快照及在模拟器运行 XCTest。
主要功能
- 01远程同步源码并构建项目
- 02选择或固定 Xcode 版本
- 03复用磁盘快照加快后续构建
- 04在模拟器运行 XCTest
- 05执行远程命令并下载文件
适用场景
- 01从非 macOS 环境构建 Apple 项目
- 02在 CI 中运行 XCTest 并检查结果
- 03为不同构建任务复用工作区快照
- 04在远程环境执行项目生成命令
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ limrun-inc/ skills --skill limrun-xcode安装后在 Claude Code 中输入/limrun-xcode确认已加载。
详细介绍
远程 Xcode 构建
在 Limrun 的远程 Xcode 上构建 Apple 项目,支持从任何环境(Linux、
Windows、macOS、VM、容器)进行构建。lim xcode build 会将源代码同步到远程
Xcode 实例,在那里进行构建,并在连接了模拟器时安装并重新启动应用。此工作流在远程实例上构建;本地 Xcode、本地模拟器和本地构建工具都不在其范围内。构建完成后,应用会在 Limrun 模拟器上运行并通过验证。
若要在应用运行后操控它(点按、输入、查看元素树、截图、
录制),请使用 limrun-ios-simulator 技能。对于 Bazel 工作区,请使用
limrun-bazel,而不是此技能。
身份验证和 CLI
如有需要,请安装:npm install --global lim。身份验证方式为 lim login 或
LIM_API_KEY(即使 .env 和 shell 中没有显示,用户的环境中也可能已设置此变量;在询问前请先检查)。CLI 是事实依据:
此技能中的命令均已验证;但如果某个标志报错,或你需要使用此处未列出的标志,请查看 --help,不要猜测:
lim xcode --help
lim xcode build --help
lim xcode run --help
构建
请使用以下命令构建,而不是使用 xcodebuild:
lim xcode build .
此命令会创建或复用已记住的 Xcode 目标,同步当前目录, 并通过 stdout 和 stderr 输出构建日志。
如果项目包含多个 scheme 或使用 workspace 文件,请使用 --scheme 和 --workspace:
lim xcode build . --scheme MyApp --workspace MyApp.xcworkspace
如需指定 Xcode 配置,请使用 --configuration Debug 或 --configuration Release。如果省略此选项,Limrun 会使用 limbuild 根据项目类型设定的默认值:原生 Xcode 构建使用 Debug,
React Native / Expo 构建使用 Release。
lim xcode build . --configuration Debug
分离构建和日志
使用 --detach 可在构建被接受后立即返回;webhook 为可选项。
logs 无需 exec ID 即可读取最新构建的日志,包括实例删除后持久保存的日志;添加 --follow 可等待构建完成。
lim xcode build . --detach
lim xcode logs
lim xcode logs --follow
选择 Xcode 版本
沙盒使用其节点的默认 Xcode 构建(目前为 26.4)。集群提供每个主版本的一个正式发布版(GA)Xcode,以及 Apple 发布种子版本期间提供的一个 Beta 版:目前有 26.4 GA、27.0 GA 和 27.1 Beta。可通过以下两种选择器指定版本:
- 仅指定主版本号(
27)时,会绑定该主版本的最新 GA 版,绝不会选择 Beta 版,并会自动跟随 Apple 发布的次要版本更新。适用于 App Store 构建。 - 指定主版本号和次版本号(
27.1)时,会固定到该确切版本。选择 Beta 版时使用这种方式。
为工作区设置一次首选版本后,之后的每次构建、测试、RBE 会话和新沙盒都会沿用该设置;命令行标志则会覆盖该设置,仅对单条命令生效:
lim xcode version list # Select is the value to type, Channel is ga or beta; * marks the one in use
lim xcode use xcode@27 # prefer the Xcode 27 GA for this workspace; switches the remembered sandbox now
lim xcode build . # builds with 27
lim xcode version # "27.0 (27A266a)" shows the sandbox's current Xcode
lim xcode version set 27.1 # pin the 27.1 beta instead
lim xcode build . --xcode-version 26 # one-off override, not remembered
lim xcode version unset # forget the preference; the sandbox goes back to the node default
使用 lim xcode use xcode@27 node@24 组合选择 Xcode 和 mise 版本。
用于脚本时,lim xcode version list --quiet 会逐行打印一个选择器(26、27、27.1),而 --json 会返回 { installed, bound, preferred }(installed[].channel 的值为 ga 或 beta)。表格会用 * 标记当前使用的 Xcode。lim xcode version set 不会记录节点上不存在的版本(错误信息会列出可用版本),但如果沙盒只是处于忙碌状态,则会保留该版本设置。
如果沙盒使用的 Xcode 与工作区首选版本不同,下一次构建时会提示这一点,并先切换版本。切换会使使用其他版本生成的构建缓存失效(下一次构建会从头开始),且在构建、同步或 lim xcode rbe 堆栈运行期间无法切换。使用持久化磁盘快照(--snapshot-key)时,请为每个 Xcode 版本线使用不同的密钥,例如 myapp-27 和 myapp-27.1:归档按密钥存储,使用不同 Xcode 恢复时会被清除。
主版本号和次版本号固定的版本会一直有效,直到集群将该版本退役;此后,lim xcode build 会报出守护进程的消息,并提示运行 lim xcode version set 27 或 lim xcode version unset。Beta 版转为 GA 版时,同一主版本号和次版本号选择器会改为指向 GA 版(需要进行一次冷构建);仅指定主版本号时,则会跟随该主版本的最新正式发布版,因此节点上的 27.1 成为 GA 版后,会立即切换到 27.1。
Apple 会拒绝从 Beta 版 Xcode 上传的 App Store 内容,因此请将 --upload-to-appstore 与仅指定主版本号的固定版本搭配使用(27,而不是 27.1)。请依据 channel 判断,而不是 betaSeed:Apple 发布的 27.1 种子版本没有种子编号。
--dev-server-url 仅适用于 React Native / Expo 构建中的 --configuration Debug。这是一个安装后启动 URL:limbuild 会验证它是否为可解析的绝对 URL,然后在连接的模拟器上安装应用后,原样打开该 URL。框架专属技能会构造正确的 URL。
lim xcode build . --configuration Debug --dev-server-url '<absolute-url>'
如果应用启动时未使用预期的 URL,请显式打开它,以区分构建/安装问题和 URL 路由问题:
lim ios open-url --id <ios-instance-id> '<absolute-url>'
磁盘快照
在多个 Xcode 实例间复用源文件、依赖项和 DerivedData。
CLI 0.35.1 及更早版本使用 --cache-* 而非 --snapshot-*,并使用
--wait-cache 而非 --wait-snapshot。快照重命名后,旧标志仍保留为别名。
在项目目录中,使用快照键创建实例,执行构建,然后删除实例:
XCODE_ID=$(lim xcode create --snapshot-key myapp-main --quiet)
lim xcode build . --id "$XCODE_ID" --scheme MyApp
lim xcode delete "$XCODE_ID" --wait-snapshot
首次运行时没有缓存;后续运行会恢复已保存的快照。成功构建且之后未进行同步时,实例终止会保存快照,并替换该键下的上一个快照。--wait-snapshot 会等待保存完成并报告结果。在 CI 中,即使构建失败,也要在清理步骤中执行删除操作。
不设置 --snapshot-paths 可保存整个工作区。多次运行时,项目文件夹名称必须保持不变。为每个项目、Xcode 版本和并发 CI 作业使用不同的键。
若要回退到其他分支的快照,请在创建时添加 --snapshot-restore-keys "myapp-pr51,myapp-main"。系统会依次尝试每个条目:先精确匹配,再匹配此前缀相同且最新的键,然后才尝试下一个条目。如果未指定此标志,保存键也会用作恢复键。若要复用快照而不保存,请只传入恢复键。
创建时配置快照。恢复键和路径之后都不能更改。
对于现有实例,只有在已启用快照的情况下,build --snapshot-key 才能绑定尚未分配的保存键;它不会恢复快照或启用快照。
请参阅磁盘快照指南,了解跳过保存、冷启动构建和 SDK 用法。
私有依赖凭据
使用 --additional-file 复制现有凭据文件;sync 也支持此参数:
lim xcode build . \
--additional-file "$HOME/.npmrc=~/.npmrc" \
--additional-file "$HOME/.netrc=~/.netrc"
远程路径中的 ~/ 指向沙盒主目录;其他目标路径均相对于工作区。后续同步时也要重复传入这些标志,以保留文件。对于配置引用的环境变量,请传入 --env。
开发者工具版本
同步后,lim xcode use 会在沙盒中选择工具并安装缺失的版本。
对于已同步项目所选用的工具,请运行 lim xcode tools install(详情)。使用主版本号;对于 Ruby、Flutter 和 Mint 等 1.0 之前的工具,使用主版本号.次版本号。
lim xcode tools
# Node includes npm/npx, Ruby includes gem, Flutter includes Dart, CocoaPods includes cocoapods-patch.
lim xcode use node@24 pnpm@10 yarn@4 bun@1 [email protected] bundler@4 cocoapods@1 \
cmake@3 java@jetbrains-21 corretto@21 [email protected] [email protected] \
xcodegen@2 xcbeautify@3 zsign@1
lim xcode tools install
lim xcode use --cwd apps/mobile node@24
lim xcode tools install --cwd apps/mobile
lim xcode run -- mise use --pin [email protected]
运行项目命令
如果仓库需要在 xcodebuild 之前或之外运行远程 macOS 命令,请使用 lim xcode run [relative-cwd] -- <command>。CLI 会先同步当前目录。工作目录相对于同步后的根目录,默认为 .:
lim xcode run -- make api
lim xcode run apps/api -- make generate
在分隔符之前传入环境变量。仅当同一实例已包含所需源文件状态时,才使用 --no-sync:
lim xcode run --env API_ENV=development -- npm run generate
lim xcode run --no-sync -- make api
沙盒包含 Node、Ruby、CMake、Mint、mise 和 Homebrew。使用 mise、Mint 或 Homebrew 安装的工具会保留在实例的沙盒主目录中,之后在该实例上运行的命令仍可使用这些工具:
lim xcode run -- 'mise trust && mise install'
lim xcode run -- 'mint install apollographql/apollo-ios-cli'
lim xcode run -- brew install tree
命令为一次性运行,且不支持交互。没有 TTY 或 stdin 通道。
下载沙盒文件
使用 lim xcode pull-file <remote-path> [destination] --id <instance-ID>。
路径可以是绝对路径,也可以相对于已同步项目的根目录。
切勿使用构建或运行日志传输文件,包括文本、二进制或 base64 内容。
请等待写入文件的命令完成。先归档目录,再下载文件,然后删除实例。
生成 Xcode 项目(XcodeGen)
如果仓库中有 project.yml,且 .xcodeproj 被 git 忽略,请勿在本地运行 xcodegen,也不要将缺少项目视为错误。远程沙盒会在构建前根据 project.yml 生成项目:
lim xcode build .
配置位于仓库根目录或下一层目录中(例如 ios/),无需传入标志。每次构建都会重新生成项目,因此只需重新构建,project.yml 的更改就会生效。已提交或强制同步的 .xcodeproj 始终优先:只有同步时未提供项目,沙盒才会生成项目。
如果仓库的代码生成步骤会生成构建所需、但被 git 忽略的输入(例如生成的本地 Swift 包或由配置派生的源文件),请先在本地运行该步骤,再使用 --include 强制同步其输出:
make generate # or whatever the repo's codegen step is
lim xcode build . --include '^ios/GeneratedKit/'
--include 接受正则表达式,类似 --ignore,而不是 gitignore 语法。要访问整个目录都被忽略的目录中的文件,模式还必须匹配目录路径本身,如上所示。
在模拟器上运行
lim xcode build 会执行构建并安装。只有在用户需要查看或操作应用时,才连接模拟器。检查 / 连接:
lim xcode get # is a simulator already attached?
lim ios create --attach # attach one (installs the last build immediately)
如果没有浏览器可供用户查看,请添加 --no-open;它会跳过在本地打开流 URL,但仍会输出该 URL,方便分享。
如果连接输出中包含已签名的流 URL,请将其作为 Markdown 链接分享给用户,例如 [实时模拟器](<signed-stream-url>)。
连接模拟器后,每次 lim xcode build 成功都会自动重新安装并重新启动应用,无需单独安装。要点按、输入、读取元素树、截屏或录制,请切换到 limrun-ios-simulator。
运行测试(XCTest)
lim xcode test 会在沙盒上构建方案中的测试目标,在已连接的模拟器上运行测试(包括单元测试和 UI 测试目标),并为每个测试用例输出一行结果。只要有测试失败,exec 就会以非零状态退出,因此可用作 CI 门禁。
lim xcode test .
lim xcode test ./MyProject --scheme MyApp
它会像 lim xcode build --ios 一样自动获取由模拟器支持的目标,并在重复运行时复用实例,因此迭代很快。方案必须配置测试操作(当项目包含测试目标时,Xcode 中的共享方案会配置此操作)。--xcode-version 27 会使用该主版本的 GA 版本构建测试(27.1 选择 beta 版);模拟器仍使用设备池的默认运行时,因此会发出警告并继续运行(可能出现依赖运行时的故障)。
使用 xcodebuild 的标识符格式 Target[/Class[/method]] 选择部分测试;多个条目可重复传入此标志。以下两个标志不能同时使用:
lim xcode test . --only-testing MyAppTests/LoginTests/testValidLogin
lim xcode test . --skip-testing MyAppUITests
只写目标名称即可选择或跳过整个目标。--only-testing 条目若指定了构建未生成的目标,运行将失败,而不会静默地运行所有测试。
如需供机器处理,--json 会以 NDJSON 格式输出原始的每个用例事件,并以 {"exitCode": N} 记录结束:
lim xcode test . --json > results.ndjson
--build-only 会编译测试目标,但不获取模拟器;生成的产物会保留在沙盒中,供之后运行。
如果 UI 测试在某个已连续运行多套测试的实例上首次交互时就失败,请优先在下次运行时使用 --inactivity-timeout 30m 获取全新实例。
已签名的设备构建(IPA)
如果用户拥有 App Store Connect 团队 API 密钥,优先使用 Apple 云签名。
Apple 会创建或复用云托管证书和描述文件,
因此用户无需提供 p12 或 .mobileprovision。密钥 ID、
签发者 ID 和 .p8 文件由用户在自己的机器上配置为
标志或环境变量;切勿在对话中询问这些值:
lim xcode build . --sdk iphoneos --configuration Release \
--signing-method release-testing --team-id "$APPLE_TEAM_ID" \
--asc-key-id "$ASC_KEY_ID" --asc-issuer-id "$ASC_ISSUER_ID" \
--asc-key AuthKey.p8 \
--upload myapp.ipa
签名方式:
debugging:为已注册的开发设备生成开发签名 IPA。release-testing:为已注册的测试设备生成分发签名 IPA。app-store-connect:为 App Store Connect 生成分发签名 IPA。
云签名需要设备 SDK(--sdk iphoneos 或 --sdk watchos)、带有签发者 ID 的
团队 API 密钥,以及与该密钥的 Apple Developer 团队匹配的 --team-id。对于分发方式,
API 密钥必须是 Admin 密钥,或启用 Access to cloud-managed distribution
certificates 权限。Cloud signing permission error 表示缺少该权限。No Account for Team 表示团队 ID 与 API 密钥不匹配。
Failed Registering Bundle Identifier 表示 Bundle ID 属于其他团队,无法自动注册。
云签名只会从 --entitlements 获取权利;绝不会从项目的 .entitlements
文件获取:归档文件未签名,而导出过程只会保留现有代码签名中的权利。任何使用
功能(HealthKit、CloudKit、应用组、推送)的应用都必须传入该标志,
否则该功能会在 IPA 中被静默移除。单独的路径指定应用;<bundleId>=<path> 指定嵌入式 Bundle(小组件、Watch 应用);
每个 Bundle 都要分别重复指定:
lim xcode build . --sdk iphoneos --configuration Release \
--signing-method release-testing --team-id VMBY3VYW4U \
--asc-key-id 2X9R4HXF34 --asc-issuer-id "$ASC_ISSUER_ID" \
--asc-key AuthKey.p8 \
--entitlements ./MyApp/MyApp.entitlements \
--entitlements com.example.myapp.widgets=./Widgets/Widgets.entitlements \
--upload myapp.ipa
plist 值必须完全展开(不能使用 $(AppIdentifierPrefix);请写入具体前缀),
必须省略由导出管理的键(application-identifier、
com.apple.developer.team-identifier、get-task-allow、
beta-reports-active),并且每项功能都必须在开发者门户的 App ID 上启用,否则导出会失败并指出该功能。
如果用户已有 p12 和描述文件,仍可使用手动签名:
lim xcode build . --sdk iphoneos --configuration Release \
--certificate-p12 dist.p12 --certificate-password "$P12_PASSWORD" \
--provisioning-profile app.mobileprovision \
--upload myapp.ipa
上传输出中包含已签名 IPA 的下载 URL。构建状态为 SUCCEEDED 表示签名已在服务器上通过 Apple 验证,因此除非用户提出要求,否则不要自行 重新验证 IPA。签名无效时,构建会明确失败,而不会生成损坏的构件。
如果应用嵌入了扩展(WidgetKit 小组件、共享表单、意图)或 Watch 应用,App Store 签名需要每个 Bundle ID 对应一个描述文件,并且这些描述文件都必须由同一分发证书签发。每个 Bundle 都要重复指定 --provisioning-profile;
系统会根据描述文件内的 application-identifier 将其与对应 Bundle 匹配,因此顺序无关:
lim xcode build . --sdk iphoneos --configuration Release \
--certificate-p12 dist.p12 --certificate-password "$P12_PASSWORD" \
--provisioning-profile app.mobileprovision \
--provisioning-profile widgets.mobileprovision \
--upload myapp.ipa
使用多个描述文件时,每个描述文件都必须包含明确的(非通配符)Bundle ID。signing preflight failed: no provisioning profile covers ...
错误会指出缺少描述文件的嵌入式 Bundle;请向用户索要 Bundle ID 完全匹配的描述文件。
请使用包含完整 CA 链的 p12,而不只是叶证书。如有需要,可重新导出并包含证书链:
openssl pkcs12 -export -inkey dist.key -in dist.pem -certfile wwdr.pem -out dist-chain.p12
构建输出中需要识别的失败字符串:
Unknown issuer hash:p12 缺少 CA 链;请按上述方法重新导出并包含证书链。code signature verification failed:平台的签名后检查拒绝了该构件。这不是用户代码的问题;请重试,如果问题持续存在则报告。- p12 密码错误:
--certificate-password与文件不匹配;用户应在自己的机器上更正该值。
上传到 App Store Connect
要将已签名的 IPA 上传到 App Store Connect,以供 TestFlight 或 App Store
分发,请在已签名的设备构建中传入 --upload-to-appstore 和 App Store Connect API 密钥
标志:
lim xcode build . --sdk iphoneos --configuration Release \
--certificate-p12 dist.p12 --certificate-password "$P12_PASSWORD" \
--provisioning-profile app.mobileprovision \
--upload-to-appstore --asc-key-id "$ASC_KEY_ID" --asc-issuer-id "$ASC_ISSUER_ID" \
--asc-key AuthKey.p8
云端签名可以使用同一 API 密钥进行签名和上传:
lim xcode build . --sdk iphoneos --configuration Release \
--signing-method app-store-connect --team-id "$APPLE_TEAM_ID" \
--asc-key-id "$ASC_KEY_ID" --asc-issuer-id "$ASC_ISSUER_ID" \
--asc-key AuthKey.p8 \
--upload-to-appstore --auto-build-number
--upload-to-appstore 需要使用云端签名或手动签名标志,以及 --asc-key-id 和
--asc-key。如果用户还希望将 IPA 存入 Asset Storage,请与 --upload <asset-name> 一起使用。
设备 IPA 会包含应用的符号文件(Payload/ 旁的 Symbols/),因此 App
Store Connect 无需单独上传 dSYM,即可对崩溃报告进行符号化处理。这要求构建生成 dSYM:默认情况下,--configuration Release 会生成;Debug 不会,因此 IPA 将不包含符号文件。
用户在自己的计算机上通过标志或环境变量提供这些信息,CLI 会在本地读取;用户不会将其粘贴到对话中。这三项信息均位于 App Store Connect 的 Users and Access 页面中,具体在 Integrations 标签页下的 App Store Connect API 区域:
--asc-key-id:API 密钥旁的 Key ID。如果用户没有密钥,请引导其使用 Developer 角色创建 Team Keys:这是能够上传构建的最低权限角色。创建团队密钥需要 Admin 账户。--asc-issuer-id:Integrations 页面顶部的 Issuer ID(团队级信息,不针对单个密钥)。云端签名需要团队密钥和此标志。手动签名并上传时,如果使用个人 API 密钥,则省略此项。--asc-key:下载的.p8文件路径。Apple 不会保留副本,离开页面后下载链接便会失效;如果用户丢失了文件,必须生成新密钥。切勿提交.p8文件或将其内容粘贴到文件中;请传入文件系统路径。
默认情况下,构建会在上传完成后立即返回,将 Apple 的处理结果留给 App Store Connect(处理通常需要很多分钟)。传入 --asc-wait-timeout <seconds>(最长 1800)即可等待结果后再返回。请从最后几行读取结果:
App Store Connect: upload accepted.:完成;Apple 处理完毕后,构建会显示在 TestFlight 中。App Store Connect: uploaded, still processing on Apple's side (upload <id>).:退出代码为 0,上传已成功;Apple 仍在处理中。请勿重试此构建。App Store Connect upload failed; the build and signing succeeded.:退出代码为 1,日志前面会显示 Apple 的错误文本。仅交付失败。
需要识别的失败信息:
- Apple 提示 bundle 版本已被使用:递增
CFBundleVersion(Expo:在 app.json 中设置expo.ios.buildNumber)并重新构建。 HTTP 401:Key ID、Issuer ID 与 .p8 不匹配,或密钥已被撤销。HTTP 403:密钥的角色无权上传构建;需要 Developer 角色或更高权限。no App Store Connect app with bundle id:应用记录不存在;用户必须在 App Store Connect 中手动创建(API 无法创建)。- 构建之后在 TestFlight 中卡在 "Missing Compliance":应用在构建时未回答出口合规问题。在 Info.plist 中将
ITSAppUsesNonExemptEncryption设为NO(Expo:在 app.json 中设置expo.ios.config.usesNonExemptEncryption: false)并重新构建。
如需自动向测试人员交付,应用的内部 TestFlight 群组必须启用自动分发(仅创建时可设置),并且必须设置上述合规密钥;这样上传后便无需任何后续操作。
预览构建
对于 Pull Request 的可重复预览,建议使用打包好的 iOS 预览操作。 它会构建并上传应用、更新 PR 预览评论,并清理构建器;输入参数和工作流示例请参阅仓库。
仅当用户要求预览构建或你要创建 PR 时,才创建可复用的预览资源。构建并上传:
ASSET_NAME="<bundle id / pr number / or any session identifier>.zip"
lim xcode build . --upload ${ASSET_NAME}
# Debug preview build:
lim xcode build . --configuration Debug --upload ${ASSET_NAME}
构建上传的默认 TTL 为 14 天:每次上传都会将资源的过期时间延后至上传时间起 14 天。传入 Go 时长(例如
720h;1d 无效)以更改此设置,使用 --upload-ttl。
然后构造预览链接,并在最后一条消息中附上该链接(如果你要创建 PR,也要在 PR 中附上):
https://console.limrun.com/stream?asset=${ASSET_NAME}&platform=ios
注意事项
- 构建错误也是工作的一部分。 如果构建失败,请阅读错误输出、修复代码并重新构建,然后再汇报。
- 项目的 mise 文件安装了构建过程中不会用到的工具。 在沙盒中首次构建或运行时,会对同步的 mise 文件中每个
[tools]条目运行mise install,因此,包含大量数据库和云 CLI 的 monorepo 根目录mise.toml会拖慢构建,甚至导致失败。项目文件可用时,请继续使用它。如果不可用,请在同一目录中添加mise.limrun.toml,仅列出构建所需的工具(例如 node 和 pnpm);在该目录中,Limrun 会读取此文件,而不是其他 mise 文件。 - 内嵌的 Xcode 沙盒已移除。 TypeScript SDK(0.54.0+)和
lim(0.35.0+)不再在 iOS 实例中创建 Xcode 沙盒。升级后可能出现以下症状:调用iosInstances.create时提示'sandbox' does not exist in type 'Spec',读取status.sandbox.xcode.url的代码提示Property 'sandbox' does not exist on type 'Status',或者lim xcode命令提示Expected an Xcode instance (sandbox_...), got ios_...。请单独创建 Xcode 沙盒并附加模拟器:使用lim ios create --xcode,或为现有模拟器运行lim xcode create --attach --simulator-id <ios-instance-id>;在 SDK 中,对客户端调用xcodeInstances.create,然后调用attachNewSimulator()或attachSimulator(iosInstance)。lim xcode命令传入sandbox_ID,lim ios命令传入ios_ID。详情: https://docs.limrun.com/docs/ios/build-with-xcode#moving-off-the-embedded-xcode-sandbox lim ios命令的实例 ID。 这些命令会根据当前工作目录所属的 git 工作树解析当前实例,如果未提供实例 ID 且没有最近使用过的 iOS 实例,可能会失败并提示No instance ID provided and no recent ios instance found。使用lim xcode get获取 ID 并传入--id <ios-instance-id>;完整操作步骤见 limrun-ios-simulator 的“Targeting the right instance”部分。- 查找 Bundle ID。 如果不知道 Bundle ID,请检查 Xcode 项目文件,或在构建成功后运行
lim ios list-apps。 - 认证错误出现在需要认证的命令上,表示会话已过期或
LIM_API_KEY有误;在用户的机器上运行lim login可续期会话。 - 构建设置会覆盖 Limrun 的默认值。
--build-setting KEY=VALUE接受任意环境变量格式的键,并替换同名的托管值。设备构建已使用标准架构(内嵌的 watch app 保留arm64_32),并禁用覆盖率检测,因此上传 App Store 无需额外设置。 - 构建成功后未找到构建产物。 服务端会自行解析已构建的 .app,即使 scheme 名称与产品名称不同也一样(例如 scheme“我的 App 开发版”构建出 MyApp-dev.app)。如果上传仍提示
built artifact not found,请显式传入完整的 Bundle 文件名,使用--artifact-name MyApp-dev.app(包含 .app 扩展名);随后服务端会从构建产物中原样获取该名称。 - 同步文件应保持精简。 单个约 2MB 或更大的文件可能会在构建开始前导致客户端同步出现 ENOMEM;请压缩大型资源。
- 符合条件的符号链接会同步。 目标为绝对路径的符号链接会被跳过并发出警告;如果构建需要它,请将其重新创建为相对路径目标。指向同步文件夹之外的相对链接会导致同步失败;请使用
--ignore忽略它,或从包含目标文件的仓库根目录进行同步。 - 签名失败会明确报错。
Unknown issuer hash表示 p12 缺少 CA 链,请连同证书链重新导出;code signature verification failed表示平台的签名后检查拒绝了构建产物,这不是代码问题,请重试或报告此问题。