TestFlight Deployment Guide¶
Complete guide for deploying Nutri-E to TestFlight via Xcode Cloud.
Quick Reference¶
App Store Connect: https://appstoreconnect.apple.com TestFlight Builds: Apps → Nutri-E → TestFlight → iOS Xcode Cloud: Apps → Nutri-E → Xcode Cloud
Current Setup (October 2025)¶
Production Status¶
- Live Version: 1.0.3 (Build 5 in Xcode Cloud / Build 29 locally)
- Deployment Method: Xcode Cloud (automatic on main branch pushes)
- Testing Group: InternalTesters
Build Numbering Note: Xcode Cloud maintains separate build numbering from local Xcode:
- Local Xcode project: CURRENT_PROJECT_VERSION = 29
- Xcode Cloud builds: Increments separately (currently Build 5)
- Both represent the same app version (1.0.3)
- See Apple's Xcode Cloud docs for details
Xcode Cloud Workflow¶
Workflow Name: Default
Trigger:
- Branch: main
- Conditions: Any changes (TODO: Add ios/** filter)
Actions: - Archive iOS app - Upload to App Store Connect
Post-Actions: - ✅ Automatic TestFlight Internal Testing distribution (Working as of Oct 24, 2025) - TODO: Add email notifications on failure
Deployment Process¶
Automatic Deployment (Xcode Cloud)¶
When you push iOS changes to main:
git checkout main
git pull origin main
# Make your changes...
git add .
git commit -m "feat: Your feature description"
git push origin main
What happens: 1. Xcode Cloud detects push to main 2. Builds and archives iOS app (Release configuration) 3. Uploads to App Store Connect 4. Processing takes 5-15 minutes 5. Automatically distributes to InternalTesters (Post-Action configured) 6. Build appears in TestFlight app automatically
That's it! No manual steps required. Just push to main and wait for TestFlight notification.
Version Bumping¶
Before deploying:
Check current version:
For bug fixes (patch):
For new features (minor):
For breaking changes (major):
Monitoring Builds¶
Option 1: App Store Connect (Web)¶
- Open https://appstoreconnect.apple.com
- Navigate: Apps → Nutri-E → Xcode Cloud
- View all builds with status: Success, Failed, In Progress
- Click any build for detailed logs
Option 2: Xcode (Recommended)¶
- In Xcode, open Report Navigator (⌘9)
- Look for "Xcode Cloud" section
- All builds show with real-time status
- Click any build for full logs
Option 3: Email Notifications¶
- Configure in Xcode Cloud Post-Actions
- "Send Email" action on failure
- Include build logs
Troubleshooting¶
Build Not Appearing in TestFlight¶
Problem: Build uploaded but not in TestFlight app
Solutions: 1. Check if build is still "Processing" (wait 5-15 minutes) 2. Verify build was added to InternalTesters group 3. Pull to refresh in TestFlight app 4. Check if Post-Action is configured for automatic distribution
Version Rejection Error¶
Problem: "This bundle is invalid. The value for key CFBundleShortVersionString [X.X.X]..."
Solution: Version train is closed, bump version:
cd ios/Nutri-E
agvtool new-marketing-version 1.0.4 # Or next version
git add Nutri-E.xcodeproj/project.pbxproj
git commit -m "chore: Bump version to 1.0.4 for TestFlight"
git push origin main
Build Fails in Xcode Cloud¶
Problem: Build fails with code signing or compilation errors
Steps: 1. Check build logs in App Store Connect → Xcode Cloud 2. Look for specific error message 3. Fix locally and test:
cd ios/Nutri-E
xcodebuild clean build \
-project Nutri-E.xcodeproj \
-scheme Nutri-E \
-configuration Release
Code Signing Issues¶
Problem: "No signing certificate..." or "No provisioning profile..."
Solution: Verify certificates in App Store Connect: 1. Settings → Certificates 2. Ensure "Apple Distribution" certificate is valid 3. Ensure App Store provisioning profile exists for bundle ID 4. Xcode Cloud uses App Store Connect's signing assets
Code Signing Setup¶
Required Certificates¶
- Type: Apple Distribution
- Team: V9GL74NMBR (Invotek AS)
- App ID: no.invotek.Nutri-E
Provisioning Profile¶
- Type: App Store
- Bundle ID: no.invotek.Nutri-E
- Devices: Not required (App Store profiles support all devices)
Xcode Cloud Signing¶
Xcode Cloud uses automatic signing with App Store Connect assets: - No need to upload certificates to GitHub - No need for manual provisioning profile management - Apple handles signing automatically
App Store Submission¶
When you're ready to submit to the App Store (not just TestFlight), follow these steps.
Prerequisites¶
Before submitting: 1. All TestFlight testing is complete 2. App metadata is prepared in App Store Connect: - Screenshots for all required device sizes - App description, keywords, support URL - Privacy policy URL - Age rating questionnaire completed 3. Version number is correct (can't reuse rejected versions)
Step 1: Archive in Xcode (Local Build)¶
Xcode Cloud builds can be promoted directly to the App Store from TestFlight. However, if you need a local archive:
cd ios/Nutri-E
# Clean build folder
xcodebuild clean -project Nutri-E.xcodeproj -scheme Nutri-E
# Archive for distribution
xcodebuild archive \
-project Nutri-E.xcodeproj \
-scheme Nutri-E \
-destination 'generic/platform=iOS' \
-archivePath ./build/Nutri-E.xcarchive
Or in Xcode GUI: 1. Select "Any iOS Device" as destination 2. Product → Archive 3. Wait for archive to complete (~5 minutes) 4. Organizer window opens automatically
Step 2: Upload to App Store Connect¶
Option A: Promote Xcode Cloud Build (Recommended)
If the build is already in TestFlight via Xcode Cloud: 1. Go to App Store Connect → Apps → Nutri-E → App Store tab 2. Click the version you're preparing (e.g., 1.0.4) 3. In "Build" section, click "+" to select a build 4. Choose the TestFlight build to promote 5. The build is now ready for App Store submission
Option B: Upload Local Archive
From Xcode Organizer: 1. Select the archive 2. Click "Distribute App" 3. Select "App Store Connect" → Next 4. Select "Upload" → Next 5. Choose signing options (usually "Automatically manage signing") 6. Review and Upload 7. Wait for upload (~5 minutes) and processing (~10-30 minutes)
Step 3: Submit in App Store Connect¶
- Open App Store Connect: https://appstoreconnect.apple.com
- Navigate: Apps → Nutri-E → App Store tab
- Select Version: Click on the version (e.g., 1.0.4)
- Complete Required Fields:
- What's New in This Version (release notes)
- Build (select uploaded/promoted build)
- App Review Information (contact info, demo account if needed)
- Review all sections for completeness (green checkmarks)
- Click "Add for Review"
- Click "Submit to App Review"
Step 4: Wait for Review¶
- Review time: Usually 24-48 hours (can be faster or longer)
- Status updates: Appear in App Store Connect and email notifications
- Possible outcomes:
- Approved: Ready for release (manual or automatic based on settings)
- Rejected: Review rejection notes provided, fix and resubmit
- In Review: Being actively reviewed
Common Rejection Reasons¶
| Rejection | Solution |
|---|---|
| ITMS-90186: "train is closed" | Version was already rejected; bump to next version |
| Guideline 2.1: Crashes or bugs | Fix bugs, test thoroughly before resubmitting |
| Guideline 4.2: Minimum functionality | Ensure app provides meaningful user experience |
| Guideline 5.1.1: Privacy | Update privacy policy, data collection declarations |
| Metadata Rejected | Fix screenshots, descriptions, or keywords |
Troubleshooting¶
"This version has already been submitted" - The version train is closed for this marketing version - Solution: Bump version number (e.g., 1.0.3 → 1.0.4)
Build not appearing in App Store Connect - Processing can take 10-30 minutes - Check email for any processing errors from Apple - Verify build uploaded successfully in Xcode Organizer
"Missing compliance" warning - Required for apps using encryption - Most apps can declare "No" for export compliance - Or add ITSAppUsesNonExemptEncryption=NO to Info.plist
Future Improvements¶
Optional: Add File Filters¶
1. Add File Filters (Optional):
- Configure "Start Conditions"
- Add "File & Folder Changes" condition
- Pattern: ios/**
- Prevents builds on non-iOS changes
- Saves Xcode Cloud build minutes
2. Add Failure Notifications (Optional): - Add "Send Email" post-action - Condition: On Failure - Include build logs
History: GitHub Actions Attempts (October 2025)¶
We initially tried GitHub Actions for TestFlight deployment but encountered persistent issues:
Issue #102: macos-15 runner simulator runtime errors - Error: "No simulator runtime version... available to use with iphonesimulator SDK" - Root cause: actool validating simulator runtimes even for device builds - Attempted 8 different fixes (PRs #93-#101) - all failed - Decision: Pivoted to Xcode Cloud (user's original suggestion)
GitHub Actions workflow preserved for reference:
- .github/workflows/deploy-testflight.yml - DO NOT USE
- .github/workflows/test.yml - iOS archive build test (works, useful for PRs)
Related Documentation¶
- CLAUDE.md - Full project architecture and services
- QUICK_REFERENCE.md - Common commands and daily workflows
- .github/WORKFLOW_GUIDE.md - Git workflow and branch protection
- CLOUDFLARE_ENVIRONMENTS.md - Worker deployment (separate from iOS)
Support¶
Apple Resources: - App Store Connect: https://appstoreconnect.apple.com - Xcode Cloud Docs: https://developer.apple.com/xcode-cloud/ - TestFlight Docs: https://developer.apple.com/testflight/
Internal: - Issues: https://github.com/Stig-Johnny/nutri-e/issues - PRs: https://github.com/Stig-Johnny/nutri-e/pulls