EAS Submit iOS:把 Expo 应用发布到 App Store
作者:Mehdi Azizi
发布于 ,8分钟
EAS Submit 只把构建上传到 TestFlight,提交审核仍需在 App Store Connect 手动完成。
eas submit --platform ios 会把你的 iOS 构建上传到 App Store Connect,经 Apple 处理后出现在 TestFlight 里。这条命令不会把你的应用提交给 Apple 审核:选择构建和提交审核,仍然要在 App Store Connect 里完成。 想让它自动运行,需要提供应用记录的编号(ascAppId)和一把 App Store Connect API 密钥。
我的 iOS 应用,包括 Solys、TradaZen 和 Nolera,都是用 Expo、EAS Build 和 EAS Submit 发布的。本指南依据 Expo 关于 iOS 提交的文档,于 2026 年 10 月 25 日重新核对过。没有 Mac 的话,完整流程见 没有 Mac 也能发布 iOS 应用。这里只讲上传这一步。
第一次运行命令前需要准备什么
Expo 列出了三个前提:
- 一个付费的 Apple Developer 账号。 价格和注册流程见 Apple 开发者账号。
ios.bundleIdentifier里的 Bundle ID。 根据 Expo 配置参考,它由你自己起,但在 App Store 上必须唯一。- 安装好 EAS CLI,然后用你的 Expo 账号执行
eas login。
你还需要一个已签名的生产构建。EAS Build 会用它替你管理的证书和描述文件来生成,详见 iOS 证书与 provisioning profile。
App Store Connect 里的应用记录:自己建还是交给 EAS?
EAS Submit 上传二进制文件的目标,必须是 App Store Connect 里已经存在的应用。
你可以自己创建。 Apple 的帮助文档 介绍了 New App 窗口:平台、名称、主要语言、Bundle ID、SKU 和用户访问权限。需要 Account Holder、Admin 或 App Manager 角色。
也可以让 EAS 在第一次上传时创建。 根据 Expo 关于 TestFlight 的页面,你上传第一个构建时,eas submit 会创建应用记录。根据 eas.json 参考,填写了 ascAppId 就会跳过这一步。名称取自 appName,没有的话取配置里的 name。主要语言取自 language,默认是 en-US。如果你的应用首发语言是中文,请在第一次上传前设置好 language。
之后,把应用记录的编号填进 ascAppId。Expo 说明了在哪里找:在 App Store Connect 里打开你的应用,进入 App Information,General Information 下的 Apple ID 字段就是。它是一串数字,不是你的 Bundle ID。
为什么用 API 密钥而不是 Apple ID
EAS Submit 可以用你的 Apple ID 或 App Store Connect API 密钥登录 Apple。
Apple ID 会卡在双重认证上,而 Apple 要求 所有 App Store Connect 用户都开启它:每次登录都得有人确认。通过 EXPO_APPLE_APP_SPECIFIC_PASSWORD 传入的 App 专用密码可以绕过这一步,但 Expo 认为它不如 API 密钥安全,后者是 Expo 默认且推荐的方式。有了密钥,认证完全不需要人工介入,也就能实现自动上传。
获取密钥有两种方式:
- 让 EAS 来管理。 运行
eas credentials --platform ios,选择production配置,登录你的 Apple 账号,然后选择“App Store Connect: Manage your API Key”。 - 使用你自己的密钥。 在 App Store Connect 里:Users and Access,Integrations 标签页,App Store Connect API,Team Keys,然后点 Generate API Key。需要 Admin 账号,Expo 的指南 给密钥分配的也是 Admin 角色。
第二种情况下,记下有效密钥列表中显示的 Key ID,以及 Integrations 页面顶部 的 Issuer ID。最重要的是保管好 .p8 文件:它只能下载一次,Apple 不会保留副本。
根据 Apple 的说法,Admin 密钥可以创建和删除你账号下的用户。Apple 要求永远不要把密钥放进代码仓库。
可直接复制的最简 eas.json
所有值都是假的:换成你自己的。
{
"cli": {
"appVersionSource": "remote"
},
"build": {
"production": {
"autoIncrement": true
}
},
"submit": {
"production": {
"ios": {
"ascAppId": "1234567890",
"appleTeamId": "ABCDE12345",
"ascApiKeyPath": "./keys/AuthKey_XXXXXXXXXX.p8",
"ascApiKeyIssuerId": "your-issuer-id",
"ascApiKeyId": "XXXXXXXXXX"
}
}
}
}
appVersionSource和autoIncrement:由 EAS 服务器保存构建号,每次生产构建自动加一。从 EAS CLI 12 起,Expo 推荐这种远程模式。ascAppId:你的应用记录编号。没有它,非交互模式会失败。appleTeamId:你的 Apple Developer 团队 ID。ascApiKeyPath、ascApiKeyIssuerId、ascApiKeyId:你的 API 密钥。这三个字段都支持环境变量。记得把keys文件夹加进.gitignore。
appleId 字段只在你用 Apple ID 登录时才需要。如果 EAS 已经在管理你的密钥,也把三个 ascApiKey 字段删掉。我在 10 月 25 日核对了自己的三个应用,生产提交配置里只有 ascAppId,Solys 多一个 appleTeamId:文件里没有任何密钥。
先构建,再上传
eas build --platform ios --profile production
eas submit --platform ios
不加其他参数时,eas submit 会让你选择要上传的构建,第一次运行还会问你的 Apple ID。如果存在 production 提交配置,就默认使用它。EAS CLI 参考 列出了可以跳过选择的参数:
| 参数 | 作用 |
|---|---|
--latest | 上传最新的 iOS 构建 |
--id | 上传指定的 EAS 构建 |
--path | 上传本地 .ipa 文件 |
--url | 上传在线归档文件 |
--groups | 加入内部测试组 |
--what-to-test | 填写“What to test” |
想一步到位,就在构建命令后加上 --auto-submit。根据 Expo 关于自动提交的页面,构建完成后会用与构建配置同名的提交配置交给 EAS Submit。要换一个配置:--auto-submit-with-profile=name。构建会进入 TestFlight,而不是进入审核。
在持续集成中,加上 --non-interactive 和 EXPO_TOKEN 令牌。此时命令无法向你提问:配置里必须有 ascAppId,还要有 API 密钥,可以是 EAS 关联到应用的那把,也可以是你填在三个 ascApiKey 字段里的那把。
上传之后会发生什么
1. Apple 处理构建。 构建必须先经过处理才会出现在 App Store Connect 里,处理完后 Apple 会给你发邮件。Expo 的说法是,一般要 10 到 15 分钟才能在 TestFlight 看到。
2. 出口合规。 Missing Compliance 状态表示你还没声明加密情况。每个新版本 App Store Connect 都会问这些问题,除非 Info.plist 已经给出答案。在 Expo 中,对应的键是 ios.config.usesNonExemptEncryption:
{
"expo": {
"ios": {
"config": {
"usesNonExemptEncryption": false
}
}
}
}
根据 Apple,如果你的应用(包括所用的库)不使用任何加密,或只使用豁免的加密,就可以填 false。系统自带的加密,比如通过 URLSession 使用 HTTPS,通常属于豁免范围。只有对你的应用确实成立时才声明 false:这份声明是要你负责的。 和 Info.plist 里的任何键一样,修改后需要重新构建。
3. TestFlight。 到了 Ready to Submit 状态,按照 Apple 的说明,构建可以发给内部测试员,可以提交 Beta 审核给外部测试员,也可以提交 App Store 审核。配置里的 groups 字段会把它加入你的内部测试组。其余内容见 用 TestFlight 测试你的应用。
上传不等于提交审核
Expo 写得很明白:TestFlight 构建不会自动发布到 App Store。EAS Submit 不会替你填写应用信息,也不会上传截图。在 App Store Connect 里还剩四步,详见 Apple 关于提交审核的帮助文档:
- 填写该版本的必填元数据。
- 在版本的 Build 部分选择构建。
- 点击“Add for Review”。 版本变成 Ready for Review,但此时还没有真正进入审核。
- 点击“Submit for Review”。 审核开始后,状态会变成 In Review。
常见错误及解决办法
| 显示的错误 | 原因 | 解决办法 |
|---|---|---|
| ITMS-90189 | 构建号已被使用 | autoIncrement |
| ITMS-90062 或 90186 | 版本已关闭 | 提高 version |
| “Set ascAppId” | CI 中缺少 ascAppId | 添加 ascAppId |
| “API Keys cannot” | 没有关联密钥 | eas credentials |
| ITMS-90683 | 缺少权限说明文字 | ios.infoPlist |
| ITMS-91053 | 隐私清单不完整 | ios.privacyManifests |
| ITMS-90725 | iOS SDK 太旧 | 升级 Expo SDK |
| Missing Compliance | 未声明加密 | usesNonExemptEncryption |
据 Expo 说,构建号重复是上传被拒的常见原因:详见 构建号与版本号。有三个错误有单独的指南:Expo 中的 ITMS-90683、Expo 中的 ITMS-91053 和 ITMS-90725。
两条带引号的消息来自 EAS,在 EAS 配置里就能解决。Missing Compliance 也可以通过在 App Store Connect 里回答问题来解决。其余各行的修复都涉及二进制文件:重新构建,然后重新上传。 远程更新改不了 Info.plist、隐私清单,也改不了版本号和构建号。
第一次上传应用,少走弯路
这条命令只是其中一步。iOS Kit 以我自己应用的 Starter Code 为基础,包含订阅功能,分四个步骤带你一直走到 App Store,节奏由你掌握。
如果你在准备第一次上架,来做免费诊断:它会告诉你真正卡住你的是什么,并把我的 Apple 防拒审清单发给你。应用信息、截图和审核通过,在 App Store 上发布应用 页面涵盖了每一步。
常见问题
如何把 Expo 应用发布到 App Store?
用 EAS Build 生成生产构建,再用 eas submit --platform ios 上传。Apple 处理完后,它会出现在 TestFlight 里。然后在 App Store Connect 里填写应用信息,在版本中选择这个构建,再依次点击“Add for Review”和“Submit for Review”。
EAS Submit 会把我的应用提交给 Apple 审核吗?
不会。EAS Submit 只把二进制文件上传到 App Store Connect,构建进入 TestFlight。提交审核需要在 App Store Connect 里手动完成,前提是应用信息已填好、构建已选定。
在哪里找到应用的 ascAppId?
在 App Store Connect 里打开你的应用,进入 App Information,General Information 下的 Apple ID 字段就是。它是一串数字,不要和 Bundle ID 搞混。
使用 eas submit 需要 Apple ID 吗?
第一次运行时,命令会向你要 Apple ID。之后,只要配置里有 ascAppId 和一把 App Store Connect API 密钥,它就能无需交互地运行,在持续集成中也一样。API 密钥是 Expo 默认且推荐的方式。
多久能在 TestFlight 里看到构建?
Expo 的说法是,Apple 处理一般需要 10 到 15 分钟,完成后会给你发邮件。如果构建停在 Missing Compliance 状态,就回答关于加密的问题,然后在配置里声明,以便后续构建使用。