关于 ios-app-store-submission
面向开发 Expo iOS 应用的团队,涵盖本地构建、TestFlight 分发及 App Store 审核提交。内容包括构建准备、环境变量管理、验证与发布前检查。
主要功能
- 01Expo 本地预构建与 Xcode 归档流程
- 02版本号与构建号检查
- 03TestFlight 环境配置
- 04App Store Connect 提交步骤
- 05发布前诊断与清理
适用场景
- 01准备 iOS 应用的 TestFlight 构建
- 02提交应用版本进行 App Store 审核
- 03排查 TestFlight 中的 API 问题
- 04归档前检查发布配置
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ kimny1143/ claude-code-template --skill ios-app-store-submission安装后在 Claude Code 中输入/ios-app-store-submission确认已加载。
详细介绍
iOS 本地构建与提交
完整工作流:本地构建 → 上传至 App Store Connect → 提交 TestFlight 测试 / 应用审核。
基本方针
- 默认使用本地构建(不使用 EAS Build)
- EAS Free tier 每月有 30 次构建额度。调试迭代会很快耗尽
- EAS 基于 git clone → 未纳入 git 的文件不会包含在构建中 → 容易出错
- 本地构建直接使用文件系统 → 安全、快速、无限制
Phase 0:构建前检查
0.1 确认应用
# どのアプリをビルドするか確認
ls -d */app.json
# → muednote-mobile/app.json, muedear/app.json
0.2 确认分支
| 用途 | 分支 |
|---|---|
| 提交 App Store 审核 | main |
| TestFlight 测试 | feature 分支也可以 |
git branch --show-current
git status
0.3 确认版本与构建编号
# app.json から現在の version と buildNumber を確認
cat <APP_DIR>/app.json | grep -E '"version"|"buildNumber"'
规则:
version:显示在 App Store 上的版本(例如:0.8.4)buildNumber:在同一version中必须唯一。始终设为现有最大值 + 1- 已在 App Store Connect 中使用过的
buildNumber不可重复使用 - version train 关闭后(例如被拒),必须提高
version
0.4 .env 管理
重要:.env 的值是在 xcodebuild archive 时由 Metro bundler 注入,而不是在 prebuild 时注入。
# 現在の .env を確認
cat <APP_DIR>/.env
# バックアップ(初回のみ)
cp <APP_DIR>/.env <APP_DIR>/.env.backup
| 用途 | CLERK_KEY | API_URL |
|---|---|---|
| 生产环境(App Store) | pk_live_... | https://mued.jp |
| 测试环境(TestFlight) | pk_test_... | preview deploy URL |
TestFlight 构建时:
# .env を TestFlight 用に変更
# EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
# EXPO_PUBLIC_API_URL=https://<preview-url>.vercel.app
生产环境构建时:
# .env が本番値であることを確認
# EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_...
# EXPO_PUBLIC_API_URL=https://mued.jp
构建后务必恢复生产环境的值:
cp <APP_DIR>/.env.backup <APP_DIR>/.env
Phase 1:本地构建
1.1 安装依赖项并执行 Prebuild
cd <APP_DIR>
npm install
npx expo prebuild --clean
--clean 会删除并重新生成 ios/。始终添加此参数。
1.2 Archive
xcodebuild -workspace ios/<SCHEME>.xcworkspace \
-scheme <SCHEME> \
-configuration Release \
-archivePath build/<SCHEME>.xcarchive \
-destination "generic/platform=iOS" \
DEVELOPMENT_TEAM=F529L4WT3V \
CODE_SIGN_STYLE=Automatic \
-allowProvisioningUpdates \
archive
各应用对应的值:
| 应用 | SCHEME | workspace |
|---|---|---|
| MUEDnote | MUEDnote | ios/MUEDnote.xcworkspace |
| MUEDear | MUEDear | ios/MUEDear.xcworkspace |
1.3 Export 并上传
xcodebuild -exportArchive \
-archivePath build/<SCHEME>.xcarchive \
-exportPath build \
-exportOptionsPlist ExportOptions.plist \
-allowProvisioningUpdates
如果没有 -allowProvisioningUpdates,会出现 "No profiles found" 错误。
1.4 ExportOptions.plist
已放置在各应用目录中。如果没有,请创建:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store-connect</string>
<key>signingStyle</key>
<string>automatic</string>
<key>teamID</key>
<string>F529L4WT3V</string>
<key>uploadSymbols</key>
<true/>
<key>destination</key>
<string>upload</string>
</dict>
</plist>
1.5 构建后恢复 .env
cp <APP_DIR>/.env.backup <APP_DIR>/.env
Phase 2:操作 App Store Connect
上传完成后,处理将在 5〜15 分钟内完成。
2.1 使用 Chrome 扩展时
可以使用 Claude in Chrome 扩展操作 App Store Connect。
1. tabs_context_mcp で接続確認
2. appstoreconnect.apple.com に navigate
3. ユーザーにログインしてもらう(パスワード入力は禁止)
4. ログイン後、アプリ一覧からスクリーンショットで状態確認
注意:
- Chrome 扩展连接不稳定。如果断开,请使用
tabs_context_mcp重新连接 - 绝对不要输入 Apple ID / 密码,请交由用户处理
- 执行「提交审核」等不可逆操作前,务必征得用户确认
2.2 发布到 TestFlight(用于测试)
- App Store Connect → 应用 → TestFlight 标签页
- 确认构建状态为「已完成」(处理完成)
- 确认 Internal Testers 群组
- 如果已自动添加,即可立即测试
- 如果没有,请从「构建」标签页添加构建
出口合规:
- 如果 app.json 中已设置
ITSAppUsesNonExemptEncryption: false,系统会自动回答 - 如果未设置,请手动选择「否」
2.3 提交 App Store 审核
⚠ 构建前请清除调试残留:
- 删除 Settings 屏幕上的 Diagnose 按钮
- 删除
apiClient.ts等文件中的调试console.log - 删除临时调试 UI(例如状态横幅)
- 确认
.env使用生产环境的值
- App Store Connect → 应用 → 分发 标签页
- 创建新版本(点击 + 按钮 → 输入版本号)
- 确认必填项:
- 屏幕截图:会从上一版本继承,但有时需要保存
- 构建:通过「添加构建」选择对应构建
- 此版本的最新动态:用英文填写更新内容
- 保存 → 添加以供审核 → 提交审核
常见错误:
| 错误 | 处理方法 |
|---|---|
| 「请选择构建」 | 构建尚未保存。重新添加并保存 |
| 「此版本的最新动态为必填项」 | 填写 What's New |
| 「需要屏幕截图」 | 新版本首次保存后会继承屏幕截图 |
| 「版本 X 的 train 已关闭」 | 提高 version(0.8.3 → 0.8.4) |
Phase 3:TestFlight 验证(UI 调试)
在 TestFlight 中看不到 console.log。 排查问题时必须在 UI 上显示调试信息。
3.0 实现面向 TestFlight 的调试诊断
在 TestFlight 构建中测试新功能或 API 集成时,务必在 Settings 屏幕上设置 Diagnose 按钮:
// Settings画面に追加
const handleDiagnose = async () => {
const lines: string[] = [];
// 1. 認証状態
lines.push(`Clerk isSignedIn: ${clerkIsSignedIn}`);
lines.push(`Clerk userId: ${clerkUserId ?? 'null'}`);
// 2. トークン取得テスト
try {
const token = await getToken();
lines.push(`Token: ${token ? `OK (len=${token.length})` : 'NULL'}`);
} catch (err: any) {
lines.push(`Token ERROR: ${err.message}`);
}
// 3. API疎通テスト(直接 fetch で生レスポンスを確認)
try {
const resp = await fetch(`${BASE_URL}/api/target-endpoint`, { headers });
const raw = await resp.json();
// apiSuccess ラップの有無を確認
lines.push(`API: ${resp.status}`);
lines.push(`Has data wrapper: ${'data' in raw}`);
lines.push(`Response keys: ${Object.keys(raw).join(', ')}`);
} catch (err: any) {
lines.push(`API ERROR: ${err.message}`);
}
Alert.alert('Diagnose', lines.join('\n'));
};
检查要点:
- 令牌为
NULL→ Clerk 会话问题 - 令牌正常,但 API 返回 401 → 服务端 JWT 验证问题
- API 返回 200,但数据为
undefined→ 响应封装(apiSuccess)未正确解包 Has data wrapper: true→ 需要在apiClient.handleResponse中解包
发布(提交审核)前务必:
- 删除 Diagnose 按钮(或将其改为连点触发的隐藏功能)
- 删除
apiClient.ts等文件中的console.log('[API] Token obtained...')等调试日志 - 删除临时调试 UI 组件(横幅、状态显示等)
- 确认以上项目后再构建并提交审核。不要在仍包含调试 UI 的情况下提交审核
Phase 4:构建前验证
4.1 Provider 不要返回 null
grep -r "return null" <APP_DIR>/src/providers/ 2>/dev/null
错误:if (!isLoaded) return null;
正确:返回加载 UI
4.2 ATT 插件配置(仅用于使用广告的应用)
grep -A5 "expo-tracking-transparency" <APP_DIR>/app.json
直接使用字符串 "expo-tracking-transparency" 是错误的。必须使用对象形式。
4.3 检查 gitignore
# modules/*/ios/ が除外されていないか確認
# ios/ ではなく /ios/ (ルート限定) であること
grep "^ios/" <APP_DIR>/.gitignore
grep "^/ios/" <APP_DIR>/.gitignore
ios/ → 排除所有层级中的 ios/(原生模块的 Swift 源文件也会被排除)
/ios/ → 仅排除根目录下的 ios/(正确)
各应用快速参考
MUEDnote
cd muednote-mobile
npm install && npx expo prebuild --clean
xcodebuild -workspace ios/MUEDnote.xcworkspace -scheme MUEDnote \
-configuration Release -archivePath build/MUEDnote.xcarchive \
-destination "generic/platform=iOS" DEVELOPMENT_TEAM=F529L4WT3V \
CODE_SIGN_STYLE=Automatic -allowProvisioningUpdates archive
xcodebuild -exportArchive -archivePath build/MUEDnote.xcarchive \
-exportPath build -exportOptionsPlist ExportOptions.plist -allowProvisioningUpdates
- Bundle ID:
com.mued.note - Apple Sign In:有
MUEDear
cd muedear
npm install && npx expo prebuild --clean
xcodebuild -workspace ios/MUEDear.xcworkspace -scheme MUEDear \
-configuration Release -archivePath build/MUEDear.xcarchive \
-destination "generic/platform=iOS" DEVELOPMENT_TEAM=F529L4WT3V \
CODE_SIGN_STYLE=Automatic -allowProvisioningUpdates archive
xcodebuild -exportArchive -archivePath build/MUEDear.xcarchive \
-exportPath build -exportOptionsPlist ExportOptions.plist -allowProvisioningUpdates
- Bundle ID:
com.mued.muedear - AdMob + ATT:有
Gotchas
- EAS Build は git clone ベース: ローカルにあっても git に入っていないファイルはビルドに含まれない。
.gitignoreのios/がmodules/*/ios/の Swift ソースまで除外していた事故例あり - version train がクローズ: App Store Connect でバージョンがリジェクト等でクローズされたら、同じバージョンでは再提出不可。version を上げる
- buildNumber は使い捨て: 一度使った buildNumber は再利用不可。App Store Connect のビルド一覧で最新番号を確認してからインクリメント
- .env はビルド後に必ず戻す: TestFlight用の
pk_testのまま本番ビルドすると事故る - prebuild の --clean は常につける: 古いネイティブコードが残って混乱する原因になる
- 新バージョンのスクショは一度保存が必要: 新バージョン作成直後はスクショが空に見えるが、保存すると前バージョンから引き継がれる
Common Rejection Reasons & Fixes
1. App Completeness(黒い画面)
Provider が null を返している。ローディング UI を返すように修正。
2. ATT Not Shown
expo-tracking-transparency のプラグイン設定がベア文字列。オブジェクト形式に変更。
3. Accurate Metadata
スクリーンショットが実際のアプリと一致しない。最新版に更新。
4. Sign In Issues
デモアカウント情報がアプリのフォームと一致しない。プレースホルダーが「メールアドレス」ならメール形式で記載。
Resolution Center コメントテンプレート
We have addressed the issue identified in the previous review:
**[Issue] (fixed)**
- Root cause: [Technical explanation]
- Fix: [What was changed]
- File changed: [File path]
Build [N] contains this fix. Thank you for your review.