ARTICLE · 1035996
不用 Mac 也能开发 iOS:Builder 把构建、签名、上架全搬到了命令行

写 iOS 应用,绕不开 Mac——至少教程都这么说。Xcode 只跑在 macOS 上,证书和描述文件传统上要用钥匙串访问做,连把构建包传上 TestFlight,苹果官方给的也是 Transporter 或在 Xcode 里点几下。主力机是 Windows 或 Linux 的人,想给自己的 Flutter、React Native 项目补一个 iOS 产物,或者只是想把写的小应用装进 iPhone 里试试,往往就卡死在这几步上。
Builder(MobAI-App/ios-builder)一个用 Go 写的开源命令行工具,MIT 协议,把这条链路整个搬到了没有 Mac 的环境里:Xcode 编译交给远端 macOS 构建机(默认 GitHub Actions,也可以选 Codemagic 或 Bitrise),签名和上架走 App Store Connect API,真机安装与热更新则靠它的配套桌面应用 MobAI。你在自己的电脑上敲命令,需要 Mac 的环节全部由远端代劳。
构建是怎么发生的

图:Builder 的两条链路——构建交给远端 macOS 机器,真机与模拟器调试通过 MobAI 完成
Builder 不是模拟 Xcode,也不是在你的电脑上跑编译——它把编译原封不动地交给一台真正的 macOS 机器。以默认的 GitHub Actions 为例,builder ios build 做的事是:把当前工作区打成一个快照,推送到仓库的一个隐藏 ref 上,触发预先写好的 workflow;macOS 构建机检出这份快照,用 Xcode 编译,把 IPA 作为构建产物传回去;命令行再把它下载到项目的 ./dist/ 目录。
两个细节值得单独说。第一,构建的是磁盘上的工作区,不是最后一次提交:没 commit 的改动、还没 git add 的新文件都会进这次构建,改完代码直接敲命令就能验证,不必为了“让 CI 编到”先制造一次提交。第二,.gitignore 依然生效,.env、GoogleService-Info.plist 这类被忽略的文件不会出现在快照里;快照本身是一次性提交,构建结束就删掉,不建分支,也不会替你往任何分支上提交东西。
框架支持是自动探测的:原生 SwiftUI、React Native、Expo(managed 和 ejected 都行)、Flutter、Kotlin Multiplatform、Cordova/Ionic,builder init 会认出项目类型并生成对应的 workflow。React Native 和 Expo 的依赖安装会沿用项目自己的包管理器(npm、Yarn、pnpm 或 Bun)和 .nvmrc 里定的 Node 版本;managed Expo 没有 ios 目录,构建机会在每次构建时用 expo prebuild 现场生成原生工程,所以本地那份过了期的 ios 目录不会被传上去。两个 Expo 的坑顺手记下:app.json 里必须写死 bundle identifier,否则 prebuild 会当场失败并点名缺什么;默认 Debug 配置构建出的包要连着 Metro 才能跑,想要独立 IPA,得在配置里把 configuration 设为 Release。
三条命令,跑通第一次构建
前提很简单:一个 iOS 项目仓库、一台能联网的电脑、一个 GitHub 账号。安装按平台挑一个——macOS 和 Linux 用 Homebrew(brew install mobai-app/tap/ios-builder)或官方安装脚本,Windows 直接去 Releases 页下载 exe 加进 PATH;想自己编译,装好 Go 后 go build 即可。
builder auth github # 授权 GitHub
builder init # 在项目目录里执行,生成 workflow
builder ios build # 触发构建,IPA 落到 ./dist/
init 会探测你的仓库和项目类型,生成 workflow 文件,然后交互式地问你要不要提交、推送并触发第一次构建。判断跑没跑通,看 ./dist/ 里有没有 IPA 就行。第一次构建前唯一容易漏的一步:生成的 workflow 文件必须提交到默认分支,否则远端什么也跑不起来。
GitHub API 不可达的环境(比如某些公司内网)还有个兜底:把要构建的内容 commit 之后打一个 ios-build/ 开头的 tag 推上去,同样能触发构建,构建结束后 tag 自动删除。
不买 Mac,真机和模拟器也能用

图:官方演示动图截帧——Windows 上的 VS Code 与 MobAI 应用,右侧是一台 USB 连接的 iPhone
构建只是第一步,调试才是日常。这里有两种玩法。
第一种是云端模拟器。builder ios share 会把工作区构建成模拟器版本,在一台远端 macOS 机器上把模拟器“开”起来,映射进 MobAI 应用——你在 Windows 上打开 MobAI,就能点按、滑动这个模拟器,像操作一台真机。模拟器会出现在 MobAI 的 CI Devices 列表里,默认闲置 30 分钟后回收,用 --duration 可以延长。它对任何 MobAI 账号免费(需要 MobAI 3.0 及以上版本),前提是在仓库里配一个 MOBAI_API_KEY 密钥——不过“免费”指的是 MobAI 这一侧,触发的那次构建照常消耗 CI 分钟数。官方还提到,接入 MobAI 的编码代理(Claude Code、Codex、Cursor)可以用同样的方式驱动这个模拟器:让 agent 自己构建、自己点界面验证,是一条挺有意思的工作流。
第二种是真机热更新,目前支持 Flutter 和 React Native。流程是:iPhone 用 USB 连到跑 MobAI 的电脑上,builder dev flutter 把构建好的 IPA 装进手机,然后盯着 lib 目录里的 .dart 文件,保存即触发热更新;.g.dart、.freezed.dart 这类生成文件默认忽略,监听目录、匹配模式和防抖时间都能在 builder.json 里调。改了 Swift、Podfile 这类原生代码才需要重新走一次构建。React Native 的热更新走 Metro,记得让手机和电脑待在同一个 Wi-Fi 里,端口被占可以用 --metro-port 换一个。
未签名的 IPA 装机时,MobAI 会问要不要用一个免费 Apple ID 现场重签(bundle id 会加一个团队 ID 后缀)。官方强烈建议为这个用途单独注册一个 iCloud 账号,别用主账号——重签会把应用和这个账号绑在一起。这条提醒值得原样听进去。Kotlin Multiplatform 则没有热更新:共享代码在构建期就编译成了原生框架,没有可替换的运行时,改一行就要重构建一次。
签名:整条链路里最“苹果”的一步
默认构建产出的是未签名 IPA。要签名,传统路径绕不开 Mac:钥匙串访问导出 .p12、开发者后台手建描述文件。Builder 把这一步也接口化了——先用 builder auth apple 存一个 App Store Connect API 密钥,之后 builder signing setup 会通过 API 替你完成全部动作:注册 App ID、在本机生成私钥并申请证书、按需注册设备、创建描述文件,最后把整套材料以密钥形式传到 GitHub 仓库,并写进 builder.json 的构建配置里。
签名配置按分发方式分成四套——development、ad-hoc、store、enterprise,各自独立成组,日常开发和上架互不干扰。应用带扩展 target(小组件、分享扩展之类)时,每个扩展也会拿到自己的描述文件。重复执行是安全的:缺什么补什么,只有证书过期或设备变更时才重建。
两个硬前提要说清楚。第一,签名需要付费的 Apple Developer Program 会员资格——苹果只给付费账号发证书,这一步绕不过去;没有的话就走未签名构建加 MobAI 免费重签的路子。第二,自动签发证书需要 Admin 角色的 API 密钥(或勾选了证书权限的 App Manager),Developer 角色的密钥能上传构建,但建不了证书。
不想全自动的人也有手动路径:builder signing csr 生成私钥和证书签发请求,去开发者网页上传换回 .cer 文件,再用 builder signing p12 把密钥和证书拼成 .p12——和钥匙串访问导出的是同一种格式,Sideloadly、AltStore 或者一台借来的 Mac 都能用。
上架:从 Windows 提交 App Store 审核
签名之后是发布。Builder 通过 App Store Connect API 完成上传和提审,全程不需要 Transporter、altool 或 Xcode,而且上传发生在你本机——CI 机器只负责构建和签名,API 密钥不离开你的电脑。
完整的一次上架长这样:
builder ios build --profile store # Release 构建 + 商店签名
builder ios upload --wait # 上传并等待苹果处理完
builder ios submit --testflight --group "Beta Testers" --notes "测试要点"
builder ios submit --app-store --release after-approval # 提交审核
嫌长可以用 ios release 一条命令串起来:它会自动取 App Store Connect 上最大的 build number 加一(避开苹果“同版本号重复上传必被拒”的 ITMS-90189 检查),然后构建、上传、等待处理、分发到 TestFlight 或提审一气呵成。TestFlight 的日常管理——建测试组、加测试员、发邀请、让过期构建失效——也有对应的 asc 命令,全部支持 --json 且从不弹交互提示,脚本和 agent 都能直接调。
上传环节有两个苹果侧的规矩要记住:build number 必须递增;导出合规问题(TestFlight 里显示 Missing Compliance)可以在 Info.plist 里把 ITSAppUsesNonExemptEncryption 写成 false 自动应答,或者上传时带 --no-encryption。另外,应用截图、描述、隐私政策这些商店元数据 Builder 不管,仍要在 App Store Connect 网页上填好——缺了这些,提审会被苹果原样拒绝。
成本:构建分钟数是主要开销
Builder 本身免费开源,花钱的地方在两处:苹果侧的付费开发者会员(固定的),和 CI 构建分钟数(弹性的)。GitHub Actions 对公开仓库的标准 runner 免费,私有仓库有免费额度;Codemagic 个人版每月含 500 分钟 macOS M2 时长;Bitrise Hobby 每月 300 credits。Codemagic 和 Bitrise 的免费套餐还会把单次工作流压在 90 分钟内(含环境准备和编译),模拟器会话也受这个上限约束。这些是各家 2026 年 9 月公开的口径,随时可能调整——重度使用前建议去各家计费页面核对,并在账单设置里关掉超额付费,避免意外扣款。
适合谁,不适合谁
适合的情况很明确:主力机是 Windows 或 Linux;团队用 Flutter、React Native 或 KMP,iOS 产物想要但不想人均一台 Mac;独立开发者想把自己的应用装上真机、送上 TestFlight;以及想把 iOS 构建交给自动化流程的人——所有 release 和 asc 命令都支持 --json、从不弹交互,显然是冲着这个场景设计的。
不适合的情况同样要直说:需要 Instruments 做性能分析、依赖 Xcode 调试器和 Interface Builder 的原生重度开发,这条远程链路帮不上忙,一台 Mac 仍然是必需品;UI 层面的调试只能靠真机上的实际表现、日志和热更新速度来感知,看不到 Xcode 里的视图层级;商店元数据管理还是要回网页。一句话总结:如果你已经有 Mac,它意义不大;如果你的 iOS 需求是“偶尔出个 IPA、跑跑真机、发发 TestFlight”,它可以帮你省下一台 Mac,把整条链路留在熟悉的命令行里。
项目地址:[github.com/MobAI-App/ios-builder](https://github.com/MobAI-App/ios-builder)