在持续集成里用 fastlane 的人,大多都有类似体验:
gym、match、build_app 一路绿灯,IPA 也顺利生成,但真正要把包送进 App Store Connect 时,问题就出现了。
- CI 环境不在 macOS
- altool / iTMSTransporter 在新版本中频繁变动
- 网络问题导致上传不稳定
- Apple 账号验证失败但信息不直观
这时候,构建流程已经自动化,上传流程却并不工程化。
为什么我没有把上传完全交给 fastlane
fastlane 本身当然可以上传,upload_to_app_store 也足够成熟。
但在一些团队环境里,它并不是最合适的选择:
- Windows CI 节点无法直接运行
- 账号需要多人共用,不适合直接暴露在 CI 配置中
- 网络环境复杂,失败后重试成本高
所以我通常把流程拆成两段:
- fastlane 负责 构建与签名
- 专用工具负责 上传与提交
fastlane 输出 IPA,本身就已经很“干净”
在 fastlane 中,我一般只做这些事情:
- 使用
match或本地证书完成签名 - 通过
gym或build_app生成 IPA - 将 IPA 输出到固定目录
这一步结束后,IPA 已经满足所有上架条件。
它并不依赖 fastlane 继续“陪跑”。
AppUploader 命令行在这里承担了什么角色
在上传这一段,我更倾向于使用 AppUploader 命令行,原因很简单:
- 不依赖 Xcode
- 可在 Windows / Linux / macOS 上运行
- 上传逻辑相对独立,失败信息更集中
在流程上,它并不参与构建,只做一件事:把一个已经准备好的 IPA,稳定地提交给 Apple。
上传流程:
在windows,linux和mac上使用命令行方式上传发布ipa到appstore的命令如下
appuploader_cli -f <ipa_file> -u
例子
appuploader_cli -u abc@icloud.com -p xxxx-xxxx-xxxx-xxxx -c 2 -f mygame.ipa
-u 指定apple开发者账号
-p 指定上传专用密码
-c 上传使用的通道,支持1和2
-f 指定要上传的ipa文件路径
appuploader目前支持通道的值 1表示是老通道,老通道稳定,2表示是新通道,新通道方便高效
appuploader_cli 在下载的appuploader压缩包内,mac版本的是在.app内的runtime目录下
一个实际可落地的组合方式
在 CI 或本地脚本中,我通常这样组织流程:
- fastlane 负责生成 IPA
- 将 IPA 放到共享目录或产物目录
- 调用 AppUploader 命令行进行上传
这样一来,构建失败和上传失败被明确区分,不会互相干扰。
使用 AppUploader 命令行前的几个准备点
在真正执行上传前,我一般会确认:
- Apple 开发者账号为已付费账号
- App Store Connect 中已有对应 App
- 已生成并配置 App 专用密码
这些条件不满足,命令行工具会明确返回错误,而不是“卡住”。
上传过程中的一些工程细节
在实践中,我更关注这些点:
- 上传通道是否可切换
- 网络异常时是否支持重试
- 错误是否能快速定位到账号、IPA 或网络
相比直接用 fastlane 上传,AppUploader 命令行更像一个上传专用模块,而不是 CI 的一部分。
当上传失败时,我是如何处理的
如果 AppUploader 返回失败,我一般不会立刻回到 fastlane:
- 构建已完成,问题不在代码
- 先检查账号权限与专用密码
- 再尝试切换上传通道
- 最后才考虑重新构建 IPA
这种分层排查方式,在多人协作中尤其重要。
在实际项目里,我更愿意看到这样的分工:
- fastlane:构建、签名、版本控制
- AppUploader:上传、提交、网络适配
- CI 系统:流程编排与触发
每个工具只做自己擅长的部分,整体反而更稳定。