| name | ios-app-store-submission |
| description | When the user wants to submit an iOS app to the App Store. Use when the user mentions 'App Store,' 'App Store Connect,' 'TestFlight,' 'iOS submission,' 'app review,' 'EAS build,' 'eas submit,' 'Apple review,' 'app rejection,' or 'iOS release.' This skill covers the entire process from setup to App Store review approval. |
iOS Local Build & Submission
ããŒã«ã«ãã«ã â App Store Connect ã¢ããããŒã â TestFlight / å¯©æ»æåºã®å®å
šã¯ãŒã¯ãããŒã
åºæ¬æ¹é
- ããŒã«ã«ãã«ããããã©ã«ãã«ããïŒEAS Buildã¯äœ¿ããªãïŒ
- EAS Free tier ã¯æ30ãã«ãããããã°å埩ã§äžç¬ã§æº¶ãã
- EASã¯git cloneããŒã¹ â gitã«å
¥ã£ãŠããªããã¡ã€ã«ã¯ãã«ãã«å«ãŸããªã â äºæ
ã®å
- ããŒã«ã«ãã«ãã¯ãã¡ã€ã«ã·ã¹ãã ãçŽæ¥äœ¿ã â å®å
šã»é«éã»ç¡å¶é
Phase 0: ãã«ãåãã§ãã¯
0.1 ã¢ããªç¹å®
ls -d */app.json
0.2 ãã©ã³ã確èª
| ç®ç | ãã©ã³ã |
|---|
| App Store å¯©æ»æåº | main |
| TestFlight ãã¹ã | feature ãã©ã³ã OK |
git branch --show-current
git status
0.3 ããŒãžã§ã³ã»ãã«ãçªå·ã®ç¢ºèª
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 ã®å€ã¯ prebuild æã§ã¯ãªããxcodebuild archive æã« Metro bundler ãæ³šå
¥ããã
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 ãã«ãã®å Žå:
æ¬çªãã«ãã®å Žå:
ãã«ãåŸã¯å¿
ãæ¬çªå€ã«æ»ã:
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 & Upload
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 ã°ã«ãŒãã確èª
- èªå远å ãããŠããã°å³ãã¹ãå¯èœ
- ãããŠããªããã°ããã«ããã¿ããããã«ãã远å
茞åºã³ã³ãã©ã€ã¢ã³ã¹:
ITSAppUsesNonExemptEncryption: false ã app.json ã«èšå®æžã¿ãªãèªååç
- æªèšå®ã®å Žåãæåã§ããããããéžæ
2.3 App Store å¯©æ»æåº
â ãã«ãåã«ãããã°æ®éªžãé€å»:
- Settingsç»é¢ã® Diagnose ãã¿ã³ â åé€
apiClient.ts çã®ãããã° console.log â åé€
- äžæçãªãããã°UIïŒã¹ããŒã¿ã¹ãããŒçïŒ â åé€
.env ãæ¬çªå€ã§ããããš â 確èª
- App Store Connect â ã¢ã㪠â é
ä¿¡ ã¿ã
- æ°ããŒãžã§ã³ãäœæïŒïŒãã¿ã³ â ããŒãžã§ã³çªå·å
¥åïŒ
- å¿
é é
ç®ã確èª:
- ã¹ã¯ãªãŒã³ã·ã§ãã: åããŒãžã§ã³ããåŒãç¶ãããããä¿åãå¿
èŠãªå Žåãã
- ãã«ã: ããã«ãã远å ããã該åœãã«ããéžæ
- ãã®ããŒãžã§ã³ã®ææ°æ
å ±: æŽæ°å
容ãè±èªã§èšèŒ
- ä¿å â 審æ»çšã«è¿œå â 審æ»ãžæåº
ãããããšã©ãŒ:
| ãšã©ãŒ | å¯ŸåŠ |
|---|
| ããã«ããéžæããŠãã ããã | ãã«ããä¿åãããŠããªããå床远å âä¿å |
| ããã®ããŒãžã§ã³ã®ææ°æ
å ±ã¯å¿
é ã | What's New ãèšå
¥ |
| ãã¹ã¯ãªãŒã³ã·ã§ãããå¿
èŠã | æ°ããŒãžã§ã³ã¯ååä¿ååŸã«ã¹ã¯ã·ã§ãåŒãç¶ããã |
| ãããŒãžã§ã³Xã®ãã¬ã€ã³ã¯ã¯ããŒãºã | version ãäžããïŒ0.8.3 â 0.8.4ïŒ |
Phase 3: TestFlight æ€èšŒïŒUIãããã°ïŒ
TestFlight ã§ã¯ console.log ã¯èŠããªãã åé¡ã®åãåãã«ã¯UIäžã®ãããã°è¡šç€ºãå¿
é ã
3.0 TestFlight åããããã°èšºæã®å®è£
TestFlight ãã«ãã§æ°æ©èœãAPI飿ºããã¹ãããå ŽåãSettingsç»é¢ã« Diagnose ãã¿ã³ ãå¿
ãèšçœ®ãã:
const handleDiagnose = async () => {
const lines: string[] = [];
lines.push(`Clerk isSignedIn: ${clerkIsSignedIn}`);
lines.push(`Clerk userId: ${clerkUserId ?? 'null'}`);
try {
const token = await getToken();
lines.push(`Token: ${token ? `OK (len=${token.length})` : 'NULL'}`);
} catch (err: any) {
lines.push(`Token ERROR: ${err.message}`);
}
try {
const resp = await fetch(`${BASE_URL}/api/target-endpoint`, { headers });
const raw = await resp.json();
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 ã»ãã·ã§ã³ã®åé¡
- ããŒã¯ã³ OK ã ã API ã 401 â ãµãŒããŒåŽã®JWTæ€èšŒã®åé¡
- API 200 ã ãããŒã¿ã
undefined â ã¬ã¹ãã³ã¹ã©ãããŒïŒapiSuccessïŒã® unwrap æŒã
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
NG: if (!isLoaded) return null;
OK: ããŒãã£ã³ã° UI ãè¿ã
4.2 ATT ãã©ã°ã€ã³èšå®ïŒåºå䜿çšã¢ããªã®ã¿ïŒ
grep -A5 "expo-tracking-transparency" <APP_DIR>/app.json
ãã¢æåå "expo-tracking-transparency" ã¯NGããªããžã§ã¯ã圢åŒãå¿
é ã
4.3 gitignore ã®ç¢ºèª
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.