手里有打好签好的 IPA,一条命令就能交给苹果,全程不需要 Mac、不需要 Xcode:
bash
appuploader-cli upload -f Payload.ipa -u dev@example.com -p abcd-efgh-ijkl-mnop
appuploader-cli 是「开心上架(AppUploader)」自带的命令行工具,upload 命令做的就是把一个已签名的 .ipa(iOS)或 .pkg(macOS)提交到 App Store Connect------和在图形界面里点「提交 App Store」是同一件事,只是可以写进脚本。
下面把这条命令的用法过一遍:两种登录方式怎么选、非 iOS 的包怎么传、怎么判断到底成没成功、传不上去时按什么顺序排查。
找到这个命令
安装「开心上架」之后,命令行工具已经跟着装好了:
| 系统 | 位置 |
|---|---|
| Windows | 主程序 AppUploader.exe 同目录下的 appuploader-cli.exe |
| macOS | AppUploader.app/Contents/Resources/appuploader-cli |
| Linux | 主程序 AppUploader 同目录下的 appuploader-cli |
在这个目录里开终端就能用。想在任意目录都能敲,把它加进 PATH:Windows 走「设置 → 系统 → 关于 → 高级系统设置 → 环境变量 → Path」,加完重开终端 才生效;macOS / Linux 在 ~/.zshrc 或 ~/.bashrc 里加一行 export PATH="$PATH:/你的安装目录"。
另外准备一个已经签好名的包 ------upload 不负责编译和签名,它的输入就是打好的 .ipa 或 .pkg。
登录方式一:App 专用密码
命令行上传最省事的凭据是 App 专用密码 。它是苹果专门为第三方工具准备的,不会触发双重验证------不用每传一次就去手机上点一次确认,这对脚本和无人值守的构建机是刚需。
去 account.apple.com/account/man... 登录,找到「App 专用密码」新建一个,会得到形如 abcd-efgh-ijkl-mnop 的密码。它只显示这一次,当场存好。
然后:
bash
appuploader-cli upload -f Payload.ipa -u dev@example.com -p abcd-efgh-ijkl-mnop
-u 是 Apple ID 邮箱,-p 是刚生成的专用密码,两个必须一起给。包的路径用 -f 指定,也可以省掉 -f 直接写在命令最后:
bash
appuploader-cli upload -u dev@example.com -p abcd-efgh-ijkl-mnop Payload.ipa
最常见的错误就是
-p填成了 Apple ID 的登录密码。专用密码固定是 16 个字母、中间三个连字符,和登录密码长得完全不一样,填之前对一眼。
登录方式二:App Store Connect API 密钥
如果这条命令要跑在团队的构建机或流水线上,用某个人的 Apple ID 就不太合适------人一走、密码一改,整条自动化就断了。这种场景改用 App Store Connect API 密钥:它属于团队而不是个人,可以单独吊销,同样不涉及双重验证。
去 appstoreconnect.apple.com/access/api 生成一把(需要 Account Holder 或 Admin 权限),拿三样东西:密钥 ID 、页面上方的 Issuer ID 、以及 .p8 私钥文件 。.p8 只能下载这一次,苹果不给第二次,立刻存进密码管理器或者 CI 的密钥仓库。
bash
appuploader-cli upload -f Payload.ipa \
--api-key UK29KBAX9X \
--api-issuer 69a6de78-4459-47e3-e053-5b8c7c11a4d1 \
--private-key AuthKey_UK29KBAX9X.p8
三个参数缺一不可。两种登录方式只能选一种 ,-u -p 和这三个参数混在一起写会被直接拒绝------从密码方式改成密钥方式时,记得把原来的 -u -p 删干净。
用密钥方式前确认两件事:
- 只能传
.ipa。 这种方式要靠包里的 Bundle ID 去 App Store Connect 上找到对应的那个 App,.pkg里取不到。macOS 的.pkg请用上面的专用密码方式。 - 这个 Bundle ID 必须已经在 App Store Connect 里建过 App。 还没建的话会提示找不到对应的 App,先去建再传。
该选哪种
一句话:自己一个人手动发版,用 App 专用密码;多人协作或者要写进流水线,用 API 密钥。
专用密码胜在简单,两个参数就能跑;但它是挂在个人 Apple ID 下的,交给流水线意味着把个人凭据交出去。API 密钥多几步配置,换来的是跟人解绑、能单独吊销、出问题只需要换这一把。
上传非 iOS 的包
默认按 iOS 处理,别的平台加 --type:
bash
# macOS 应用
appuploader-cli upload -u dev@example.com -p abcd-efgh-ijkl-mnop --type osx App.pkg
# tvOS
appuploader-cli upload -f App.ipa -u dev@example.com -p abcd-efgh-ijkl-mnop --type appletvos
一共四个值:ios(默认)、osx、appletvos、xros(visionOS)。
怎么判断到底传成功没有
回车之后进度会一行行实时打出来,包越大跑得越久。看最后一行:
markdown
> upload finished successfully
失败则是:
vbnet
> upload finished with error: <苹果给出的具体原因>
如果是写脚本,不要去 grep 这些日志------命令失败时退出码是非 0,判断退出码就够了,也不会因为日志文案变化而失灵:
bash
set -e
appuploader-cli upload -f build/App.ipa -u "$APPLE_ID" -p "$APP_PASSWORD"
Windows PowerShell 里:
powershell
& appuploader-cli.exe upload -f .\build\App.ipa -u $env:APPLE_ID -p $env:APP_PASSWORD
if ($LASTEXITCODE -ne 0) { throw "上传失败" }
还有一点容易误解:命令返回成功,只表示苹果收下了这个包并通过了初步校验。苹果那边还要处理几分钟到几十分钟,处理完才会出现在 App Store Connect 的「构建版本」列表里,那之后才能选来提审。刚传完看不到属于正常。
传不上去,按这个顺序排查
第一类:命令还没跑起来就退出了。 这类问题在本机,改完立刻能验证。
- 提示
file not found:路径不对。在 CI 里最常见的原因是当前工作目录不是你以为的那个,脚本里尽量用绝对路径。 - 提示两种登录方式不能混用:
-u/-p和--api-key/--api-issuer/--private-key只能留一组。 - 提示
not a valid PEM file或expected PKCS8:--private-key指的不是苹果给的那个.p8,或者文件内容坏了。CI 里最常见的原因是把.p8存进 Secret 时丢了换行,重新完整复制原文件再存一遍。 - 提示
the ipa has no CFBundleIdentifier:用密钥方式传了非 IPA 的包,换回专用密码方式。
第二类:包传上去了,但被苹果退回来。 这类原因都写在 upload finished with error: 后面,常见的几种:
- 版本号/构建号重复 :同一个
CFBundleShortVersionString+CFBundleVersion组合已经传过一次。苹果不允许覆盖,改构建号重新打包。 - 签名不匹配:包用的证书或描述文件不是 App Store 分发用的。检查打包时选的是不是 App Store 类型的描述文件。
- Info.plist 缺字段 :常见的是缺图标、缺必需的用途说明(相机、相册、定位等的
NSxxxUsageDescription)、或者缺少某些设备能力声明。按提示补齐重新打包。 - 找不到对应的 App:这个 Bundle ID 还没在 App Store Connect 里创建 App。
这条命令配好之后基本不用再管,发版时敲一次或者交给 CI 跑就行。同一个工具在 Windows 上还能签证书、建 Bundle ID、生成描述文件,我这边整条 iOS 发布链路就是这么绕开 Mac 的。