Here are the errors repeatedly encountered while uploading multiple Flutter apps to TestFlight.
1. Apple Sign-In Error 1000
SignInWithAppleAuthorizationException(AuthorizationErrorCode.unknown,
The operation couldn't be completed.
(com.apple.AuthenticationServices.AuthorizationError error 1000.))
Cause
This occurs because the Sign in with Apple capability is missing from Runner.entitlements.
Solution
Both places must be configured.
1. ios/Runner/Runner.entitlements
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
2. Apple Developer Console
developer.apple.com -> Identifiers -> Select app Bundle ID -> Check Sign in with Apple -> Save
If a provisioning profile already exists, it needs to be regenerated.
If you only modify the entitlements file without activating it in the Console, error 1000 still occurs.
2. Google OAuth Error 400: invalid_request
Error 400: invalid_request
Request details: flowName=GeneralOAuthFlow
When attempting login with the Flutter google_sign_in package, the Google login screen does not appear and a 400 error occurs in the browser.
Root Cause Analysis
When login fails, the redirect URL contains an authError parameter. Base64 decoding reveals the actual cause.
python3 -c "
import base64
encoded = '<authError parameter value>'
print(base64.b64decode(encoded + '==').decode('utf-8', errors='replace'))
"
# Result: "Custom scheme URIs are not allowed for 'WEB' client type."
Cause
The CLIENT_ID in GoogleService-Info.plist was a Web type OAuth client.
The google_sign_in package redirects using the custom URL scheme of an iOS-type client (com.googleusercontent.apps.{ID}:/oauthredirect). Web type does not allow this method.
Solution
You must create a new iOS type OAuth client in Google Cloud Console.
- Application type:
iOS(not Web) - Bundle ID: Enter the app bundle ID
- Team ID: Apple team ID
After creation, download the .plist file and update three places.
1. ios/Runner/GoogleService-Info.plist
<key>CLIENT_ID</key>
<string>{iOS_CLIENT_ID}.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.{iOS_CLIENT_ID}</string>
2. ios/Runner/Info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.{iOS_CLIENT_ID}</string>
</array>
</dict>
</array>
3. Backend environment variable
GOOGLE_CLIENT_ID={iOS_CLIENT_ID}.apps.googleusercontent.com
When the backend verifies the JWT aud claim, it must match the iOS CLIENT_ID.
iOS-type OAuth clients cannot be created via CLI or Firebase SDK. It is only possible through the Google Cloud Console UI.
3. Provisioning Profile Entitlements Mismatch
Provisioning profile "iOS Team Provisioning Profile: com.example.app"
doesn't match the entitlements file's value for the
com.apple.developer.default-data-protection entitlement.
Cause
This occurs when a capability declared in Runner.entitlements is not included in the current provisioning profile.
Common problematic items:
com.apple.developer.default-data-protectioncom.apple.developer.icloud-container-identifierscom.apple.developer.icloud-services
Solution
Choose one of two approaches.
Option A: Enable capability in Apple Developer Console
Enable the required capability on the App ID and regenerate the provisioning profile.
Option B: Remove unused entitlements (recommended)
If the app does not actually use the capability, remove it from Runner.entitlements.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "...">
<plist version="1.0">
<dict>
<!-- Keep only what is actually used -->
<key>aps-environment</key>
<string>production</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
</dict>
</plist>
default-data-protectionis a security policy setting, so removing it does not affect app behavior.
4. Xcode Manual Signing Conflicts with Automatic Signing
Runner has conflicting provisioning settings. Runner is automatically signed,
but provisioning profile PROFILE_NAME has been manually specified.
Cause
A specific provisioning profile is hardcoded in project.pbxproj while the build command requests Automatic signing, causing a conflict.
Solution
Change manual signing settings to Automatic in ios/Runner.xcodeproj/project.pbxproj.
sed -i '' \
-e 's/CODE_SIGN_STYLE = Manual;/CODE_SIGN_STYLE = Automatic;/g' \
-e 's/CODE_SIGN_IDENTITY = "iPhone Distribution";/CODE_SIGN_IDENTITY = "iPhone Developer";/g' \
-e '/PROVISIONING_PROFILE_SPECIFIER = ".*";/d' \
ios/Runner.xcodeproj/project.pbxproj
5. TestFlight Upload Failure: Missing BGTaskSchedulerPermittedIdentifiers
Missing Info.plist value. The Info.plist key 'BGTaskSchedulerPermittedIdentifiers'
must contain a list of identifiers used to submit and handle tasks
when 'UIBackgroundModes' has a value of 'processing'.
Cause
When UIBackgroundModes in Info.plist contains processing, BGTaskSchedulerPermittedIdentifiers must also be present. This combination typically arises when using the workmanager package.
Solution
Check the task names passed to registerPeriodicTask or registerOneOffTask in the code, then add them to Info.plist.
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>your_task_name_here</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
</array>
Verify task names in Dart code:
grep -r "registerPeriodicTask\|registerOneOffTask" lib/ --include="*.dart"
6. Two-Stage Build Instead of flutter build ipa
flutter build ipa handles the entire build including codesigning in one step. It is prone to failure with entitlements issues or when no Xcode account is logged in.
Splitting into two stages is more reliable.
# Stage 1: Build app without codesigning
flutter build ios --release --no-codesign
# Stage 2: Archive directly with App Store Connect API Key
xcodebuild archive \
-workspace ios/Runner.xcworkspace \
-scheme Runner \
-configuration Release \
-archivePath build/ios/archive/Runner.xcarchive \
-allowProvisioningUpdates \
-authenticationKeyPath /path/to/AuthKey_KEYID.p8 \
-authenticationKeyID YOUR_KEY_ID \
-authenticationKeyIssuerID YOUR_ISSUER_ID \
CODE_SIGN_STYLE=Automatic \
DEVELOPMENT_TEAM=YOUR_TEAM_ID
# Stage 3: IPA export
xcodebuild -exportArchive \
-archivePath build/ios/archive/Runner.xcarchive \
-exportPath build/ios/ipa \
-exportOptionsPlist ios/ExportOptions.plist \
-allowProvisioningUpdates \
-authenticationKeyPath /path/to/AuthKey_KEYID.p8 \
-authenticationKeyID YOUR_KEY_ID \
-authenticationKeyIssuerID YOUR_ISSUER_ID
# Stage 4: TestFlight upload
xcrun altool --upload-app \
--type ios \
--file "build/ios/ipa/app.ipa" \
--apiKey YOUR_KEY_ID \
--apiIssuer YOUR_ISSUER_ID
Including API Key info in ExportOptions.plist allows the export stage to work without an account as well.
<key>authenticationKeyID</key>
<string>YOUR_KEY_ID</string>
<key>authenticationKeyIssuerID</key>
<string>YOUR_ISSUER_ID</string>
<key>authenticationKeyPath</key>
<string>/path/to/AuthKey_KEYID.p8</string>
Wrapping it in a Makefile lets you finish with a single make testflight.
Checklist
Items to verify before TestFlight deployment:
- Only used capabilities are declared in
Runner.entitlements - Those capabilities are activated on the App ID in Apple Developer Console
- If
UIBackgroundModes: processingexists,BGTaskSchedulerPermittedIdentifiersis also present - Google OAuth CLIENT_ID is iOS type, not Web type
- No hardcoded provisioning profiles in
project.pbxproj - Build number is higher than the previous upload

💬 댓글
비밀번호를 기억해두면 나중에 내 댓글을 삭제할 수 있어요.