Release and TestFlight Workflow
Quick path: Adding testers to an existing build
If the user only asks to add/invite a beta tester (NOT build + upload), skip the full workflow. Follow these steps in exact order:
# 1. Check if there are any builds available
asc builds list --app "APP_ID" --limit 3 --output json
If NO builds exist: Tell the user they need to upload a build first. Offer to run the full build+upload workflow (Step 1-9 below). Do NOT add testers without a build.
If builds exist: Continue with external testing below.
Adding a beta tester (external testing)
External testing works for any email — the tester does NOT need to be an App Store Connect team member. However, external testing requires Beta App Review before the tester can install.
# 2. List existing external groups, or create one
asc testflight beta-groups list --app "APP_ID" --output json
asc testflight beta-groups create --app "APP_ID" --name "Beta Testers"
# 3. Assign the latest build to the external group
asc builds add-groups --build "BUILD_ID" --group "GROUP_ID"
# 4. Add the tester to the group (works for any email)
asc testflight beta-testers add --app "APP_ID" --email "tester@example.com" --group "Beta Testers"
Now you MUST ask the user for confirmation before submitting for Beta App Review. Say:
"I've added tester@example.com to the Beta Testers group. To complete the invitation, this build needs to be submitted for Beta App Review (Apple reviews it, typically < 24 hours). Once approved, the tester will automatically receive a TestFlight invitation email. Shall I submit for Beta App Review?"
Wait for the user's response. Only proceed if they confirm:
# 5. Submit for Beta App Review (only after user confirms)
asc testflight review submit --build "BUILD_ID" --confirm
# 6. Check review status
asc testflight review submissions list --build "BUILD_ID"
Do NOT call asc testflight beta-testers invite for external testers — it will fail with "Tester has no installable build" until Beta App Review is approved. Once approved, the tester automatically receives the invitation.
Internal testing (advanced — team members only)
Internal testing is only for people who are already App Store Connect team members. Internal groups auto-receive all builds and testers get instant access (no review). Use this only when the user explicitly asks for internal testing or the tester is a known team member.
asc testflight beta-groups create --app "APP_ID" --name "Internal Testers" --internal
asc testflight beta-testers add --app "APP_ID" --email "tester@example.com" --group "Internal Testers"
asc testflight beta-testers invite --app "APP_ID" --email "tester@example.com"
Do NOT use asc builds add-groups for internal groups — they auto-receive all processed builds.
Preconditions
- You MUST build the IPA first using
xcodebuild archive+xcodebuild -exportArchive(see asc-xcode-build skill). - Ensure credentials are set (
asc auth loginorASC_*env vars). - Use a new build number for each upload.
- Prefer
ASC_APP_IDor pass--appexplicitly. - Build must have encryption compliance resolved (see asc-submission-health skill).
Preferred end-to-end commands
- TestFlight:
asc publish testflight --app <APP_ID> --ipa <PATH> --group <GROUP_ID>[,<GROUP_ID>]- Optional:
--wait,--notify,--platform,--poll-interval,--timeout
- App Store:
asc publish appstore --app <APP_ID> --ipa <PATH> --version <VERSION>- Optional:
--wait,--submit --confirm,--platform,--poll-interval,--timeout
Full build + upload + distribute workflow
This is a MANDATORY step-by-step workflow. When the user asks to publish/build/upload to TestFlight, you MUST execute ALL steps below in order. Do NOT skip any step. Do NOT claim the app is "already on TestFlight" without verifying. Do NOT stop after planning — execute the commands.
Step 1: Find and regenerate the Xcode project
# Find .xcodeproj or .xcworkspace
find . -maxdepth 2 -name "*.xcworkspace" -o -name "*.xcodeproj" | head -5
If a project.yml exists (XcodeGen project), always regenerate the .xcodeproj first:
xcodegen generate
This ensures all build settings (CFBundleIconName, icon assets, etc.) are current in the .xcodeproj.
If a .xcworkspace exists, use -workspace flag. Otherwise use -project flag.
Step 2: Determine the scheme
# List available schemes
xcodebuild -list
Pick the main app scheme (not tests, not UI tests).
Step 3: Check current build number
# Get current build settings
xcodebuild -showBuildSettings -scheme "SCHEME" | grep -E "CURRENT_PROJECT_VERSION|MARKETING_VERSION"
Also check the latest build on ASC:
asc builds list --app "APP_ID" --limit 3 --output json
If the local build number is not higher than the latest uploaded build, increment it:
# Find the project.pbxproj or xcconfig and update CURRENT_PROJECT_VERSION
Step 4: Add ITSAppUsesNonExemptEncryption to Info.plist
Check if ITSAppUsesNonExemptEncryption is set. If not, add it to avoid encryption compliance issues:
# Check in Info.plist or build settings
grep -r "ITSAppUsesNonExemptEncryption" . --include="*.plist" --include="*.pbxproj"
If missing, add ITSAppUsesNonExemptEncryption = NO to the app's Info.plist.
Step 5: Clean and archive
xcodebuild clean archive \
-scheme "SCHEME" \
-configuration Release \
-archivePath /tmp/APP_NAME.xcarchive \
-destination "generic/platform=iOS" \
-allowProvisioningUpdates \
AUTHENTICATION_KEY_PATH AUTH_FLAGS_IF_AVAILABLE
If API key authentication flags are provided in the system prompt, include them:
-authenticationKeyPath <path>-authenticationKeyID <id>-authenticationKeyIssuerID <issuer>
This step MUST succeed. If it fails, diagnose the error and fix it before proceeding.
Step 6: Create ExportOptions.plist
cat > /tmp/ExportOptions.plist << '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>destination</key>
<string>upload</string>
</dict>
</plist>
PLIST
If you know the team ID, add it:
<key>teamID</key>
<string>TEAM_ID</string>
Step 7: Export IPA
xcodebuild -exportArchive \
-archivePath /tmp/APP_NAME.xcarchive \
-exportPath /tmp/APP_NAME_Export \
-exportOptionsPlist /tmp/ExportOptions.plist \
-allowProvisioningUpdates \
AUTHENTICATION_KEY_PATH AUTH_FLAGS_IF_AVAILABLE
This step MUST succeed. The IPA file will be at /tmp/APP_NAME_Export/APP_NAME.ipa.
Step 8: Upload to App Store Connect
asc builds upload --app "APP_ID" --ipa "/tmp/APP_NAME_Export/APP_NAME.ipa"
Wait for the upload to complete.
Step 9: Wait for build processing
After upload, the build needs time to process on Apple's servers:
# Check if the build is processed
asc builds latest --app "APP_ID" --output json
If the build is still processing, wait and check again. Use asc builds info --build BUILD_ID to check status.
Step 10: Distribute to TestFlight
Default: External testing (works for any email)
# 1. Create an external group and assign the build
asc testflight beta-groups create --app "APP_ID" --name "Beta Testers"
asc builds add-groups --build "BUILD_ID" --group "GROUP_ID"
# 2. Add tester to the group (works for any email)
asc testflight beta-testers add --app "APP_ID" --email "tester@example.com" --group "Beta Testers"
Now ask the user for confirmation before submitting for Beta App Review:
"I've added the tester to the Beta Testers group. To complete the invitation, this build needs to be submitted for Beta App Review (typically < 24h). Once approved, the tester will automatically receive a TestFlight invitation. Shall I submit?"
# 3. Submit for Beta App Review (only after user confirms)
asc testflight review submit --build "BUILD_ID" --confirm
# 4. Check submission status
asc testflight review submissions list --build "BUILD_ID"
Do NOT call beta-testers invite for external testers — it fails with "Tester has no installable build" until review is approved. Once approved, testers automatically receive the TestFlight invitation.
Step 11: Verify and report
# Verify the build is on TestFlight
asc builds info --build "BUILD_ID" --output json
Report to the user:
- Build version and number
- Upload status
- TestFlight group(s) assigned
- Any warnings or issues
App Store submission (after upload)
For App Store (not TestFlight), attach the build to a version and submit:
# Attach build to version
asc versions attach-build --version-id <VERSION_ID> --build <BUILD_ID>
# Submit for review
asc submit create --app <APP_ID> --version <VERSION> --build <BUILD_ID> --confirm
# Check or cancel submission
asc submit status --id <SUBMISSION_ID>
asc submit cancel --id <SUBMISSION_ID> --confirm
macOS Release
macOS apps are distributed as .pkg files, not .ipa.
Upload PKG
asc builds upload \
--app <APP_ID> \
--pkg <PATH_TO_PKG> \
--version <VERSION> \
--build-number <BUILD_NUMBER> \
--wait
Notes:
--pkgautomatically sets platform toMAC_OS.- For macOS
.pkg, useasc builds upload --pkg+ attach/submit steps.
Attach and Submit (macOS)
Same as iOS flow:
asc builds list --app <APP_ID> --limit 5
asc versions attach-build --version-id <VERSION_ID> --build <BUILD_ID>
asc review submissions-create --app <APP_ID> --platform MAC_OS
asc review items-add --submission <SUBMISSION_ID> --item-type appStoreVersions --item-id <VERSION_ID>
asc review submissions-submit --id <SUBMISSION_ID> --confirm
visionOS / tvOS Release
Same as iOS flow, use appropriate --platform: VISION_OS or TV_OS.
Pre-submission Checklist
Before submitting to App Store, verify:
- [ ] Build status is
VALID(not processing) - [ ] Encryption compliance resolved
- [ ] Content rights declaration set
- [ ] Copyright field populated
- [ ] All localizations complete
- [ ] Screenshots present
See asc-submission-health skill for detailed preflight checks.
Manage groups and testers
After distribution, these commands manage TestFlight access:
- Groups:
asc testflight beta-groups list --app "APP_ID" --paginateasc testflight beta-groups create --app "APP_ID" --name "Beta Testers"(external, default)asc testflight beta-groups create --app "APP_ID" --name "Internal Testers" --internal(team members only)
- Testers:
asc testflight beta-testers list --app "APP_ID" --paginateasc testflight beta-testers add --app "APP_ID" --email "tester@example.com" --group "Beta Testers"asc testflight beta-testers remove --app "APP_ID" --email "tester@example.com"
What to Test notes
asc builds test-notes create --build "BUILD_ID" --locale "en-US" --whats-new "Test instructions"asc builds test-notes update --id "LOCALIZATION_ID" --whats-new "Updated notes"
Critical rules
- NEVER skip the build/archive/export steps when doing a full publish. The IPA must be built fresh.
- NEVER assume a build is already on TestFlight without checking.
- Default to external testing for beta testers. Only use internal testing when the user explicitly asks or the tester is a known ASC team member.
- ALWAYS ask the user for confirmation before submitting for Beta App Review (
asc testflight review submit). - Do NOT call
beta-testers invitefor external testers — it fails before review approval. Testers are auto-invited once approved. - Do NOT use
asc builds add-groupsfor internal groups — they auto-receive builds. - If any step fails, diagnose the error, fix it, and retry that step.
- Use
--paginateon large groups/tester lists. - Prefer IDs for deterministic operations.
- Always use
--helpto verify flags for the exact command.
微信扫一扫