Skip to content

michaelayoade/flutter-xcode-cloud-starter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Flutter on Xcode Cloud — the missing manual

Shipping a Flutter app to TestFlight via Xcode Cloud sounds like a checkbox. In practice it's a gauntlet of undocumented failures — Xcode Cloud doesn't know what Flutter is, SwiftPM resolution breaks, exports fail for reasons nobody explains, and the build logs live behind Apple auth where you can't grep them.

This repo is the set of working CI scripts, a CLI to read your Xcode Cloud builds from the terminal, and a gotchas guide that gets a Flutter app building on Xcode Cloud and delivering to TestFlight — including FCM push.

Everything here was distilled from getting a real production Flutter app green on Xcode Cloud. Each fix maps to a specific wall you will hit.

license PRs welcome


The walls (and the fix for each)

# The wall The fix
1 Xcode Cloud builds, but it has no idea what Flutter is → missing SDK / frameworks / pods ci_scripts/ci_post_clone.sh installs Flutter + generates the iOS artifacts
2 Could not resolve package dependencies … 'flutterfire' was added Commit Package.resolved AND pin the Flutter version (GOTCHAS #2)
3 Archive fails: your team has no devices … No profiles for … Register one device — Xcode Cloud needs it to build the dev/ad-hoc exports (GOTCHAS #3)
4 App Store rejects build: Missing Compliance ITSAppUsesNonExemptEncryption in Info.plist (GOTCHAS #4)
5 ITMS-90683: Missing purpose string from a plugin you don't think you use Add the purpose strings the SDK references (GOTCHAS #5)
6 You want FCM push, but the plist is gitignored Materialize it from a base64 secret + wire it in CI (wire_firebase.rb, GOTCHAS #6)
7 "Build failed" — but the logs are locked in App Store Connect tools/asc_ci.py reads them from your terminal

Full write-up: docs/GOTCHAS.md.


Quick start

1. Drop in the CI hook

Copy ci_scripts/ into your Flutter project's ios/ folder and make it executable:

cp -r ci_scripts <flutter-project>/ios/ci_scripts
chmod +x <flutter-project>/ios/ci_scripts/ci_post_clone.sh

Xcode Cloud auto-runs any ci_scripts/ci_post_clone.sh next to the Xcode project.

2. Set Xcode Cloud environment variables

In your workflow → Environment → Environment Variables:

Name Required Notes
FLUTTER_VERSION Pin it (e.g. 3.44.1) — must match your committed Package.resolved
FLUTTER_PROJECT_PATH Path to the Flutter project in the repo (default .; e.g. mobile for a monorepo)
API_BASE_URL Example --dart-define; add your own
GOOGLE_SERVICE_INFO_PLIST_B64 base64 of GoogleService-Info.plist to enable FCM push (mark Secret)

3. Commit your Package.resolved (the #1 cause of mysterious failures)

flutter pub get
cd ios && open Runner.xcworkspace   # let Xcode resolve packages, then:
git add ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved

And register one device in the Apple Developer portal (GOTCHA #3).

That's the 90% that gets you green. The rest (compliance, purpose strings, push) is in the gotchas.


asc_ci — read your Xcode Cloud builds from the terminal

GitHub only shows pass/fail; the real logs are in App Store Connect. asc_ci.py pulls the failing steps + error messages over the App Store Connect API — no third-party dependencies (it signs the ES256 JWT with openssl + the stdlib).

# one-time: App Store Connect → Users and Access → Integrations → generate an API key
mkdir -p ~/.config/asc-ci && cat > ~/.config/asc-ci/config <<EOF
ASC_ISSUER_ID=<issuer-uuid>
ASC_KEY_ID=<key-id>
ASC_KEY_FILE=~/Downloads/AuthKey_XXXX.p8
ASC_APP_ID=<your-app-apple-id>
EOF

python3 tools/asc_ci.py latest 3      # last 3 builds, with each failing action's errors
python3 tools/asc_ci.py issues <id>   # one build action's issues
python3 tools/asc_ci.py get /v1/ciProducts

Example output:

=== Build #58 | COMPLETE / FAILED ===
  • Archive - iOS [ARCHIVE] FAILED (errors=2, warnings=1)
      [ERROR] ValidationStep
        Could not resolve package dependencies: a resolved file is required ...

What's here

ci_scripts/ci_post_clone.sh   Xcode Cloud hook: install Flutter + generate iOS artifacts (+ optional FCM)
ci_scripts/wire_firebase.rb   add GoogleService-Info.plist + push entitlement to the Runner target
tools/asc_ci.py               read Xcode Cloud build results from the CLI (ASC API, zero deps)
docs/GOTCHAS.md               every wall and its fix, in detail

Contributing

Hit a wall this doesn't cover? PRs and issues welcome — the goal is to be the page you wish you'd found. See CONTRIBUTING.md.

License

MIT.

About

Ship Flutter to TestFlight via Xcode Cloud — working CI scripts, an ASC build-log CLI, and the gotchas nobody documents

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors