chore(samples): xcode 27, no cocoapods, SPM re-enabled - #2951
Conversation
Moves the sample app's iOS build to Swift Package Manager and removes the CocoaPods integration from both the iOS and macOS Runner projects. `media_kit_video` was the only remaining pod-only plugin. It backed `SampleAppVideoPlayer`, whose desktop branch is gated on Windows/Linux — platforms the sample app has no runner directories for — so on every platform it can actually be built for the widget already fell through to `DefaultStreamVideoPlayer`. Dropping the dependency leaves iOS, macOS, Android and web behaviour unchanged and makes every remaining plugin SPM-compatible. macOS deployment target goes 11.5 -> 12.0, the floor Flutter 3.47 declares in its generated `FlutterMacOS.podspec` and uses in its own app template; below it the build fails to resolve. The highest floor any plugin asks for is 11.0. CI iOS jobs move to the `xcode-27` runner image with `xcode-version: latest`, and the "Disable Swift Package Manager" steps are gone — with them the tool would regenerate a Podfile and link plugins through CocoaPods again. The pod cache action is deleted along with its last consumers; the SwiftPM equivalent is ~1.5 GB, too large to be worth caching. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review. 📝 WalkthroughWalkthroughThe change removes CocoaPods from Flutter Apple examples, links Flutter-generated Swift packages, raises Apple deployment targets, updates Flutter app lifecycle configuration, removes the sample desktop media player, and centralizes Xcode setup in reusable CI actions. ChangesApple platform migration
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Workflow
participant SetupXcode
participant FlutterBuild
participant SwiftPM
Workflow->>SetupXcode: Select Xcode version
Workflow->>FlutterBuild: Run Flutter bootstrap
Workflow->>SwiftPM: Restore Swift package cache
FlutterBuild->>SwiftPM: Build with FlutterGeneratedPluginSwiftPackage
Suggested reviewers: Merge Risk: ⚪ Minimal · up to The change migrates Apple examples to Swift Package Manager, removes CocoaPods, and updates CI and platform settings. Reported builds and local runs pass, with no concrete merge-blocking risk identified. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 7 files. (3 skipped: 3 unsupported.)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2951 +/- ##
=======================================
Coverage 75.85% 75.85%
=======================================
Files 442 442
Lines 28776 28776
=======================================
Hits 21828 21828
Misses 6948 6948 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Restores what #2672 / #2675 worked around, rather than re-disabling SPM. `FLUTTER_XCODE_CODE_SIGN_IDENTITY` / `..._PROVISIONING_PROFILE_SPECIFIER` reach xcodebuild as command-line build settings, and those apply to every target in the build graph. With CocoaPods that was harmless — podhelper.rb sets `CODE_SIGNING_ALLOWED = NO` on pod resource bundles and on Pods-Runner. Swift Package plugin bundles have no such hook, so they inherited the app's manual identity and failed the archive with `Signing for "<plugin>" requires a development team` — 40+ of them. Writing the same two settings into Flutter/Signing.xcconfig instead fixes it: Flutter/Release.xcconfig is the base configuration of the Runner target alone (the project-level configurations have no xcconfig), and Runner's Release config leaves identity and profile unset, so an xcconfig can supply them. Verified locally via `fastlane ios build_ipa export_method:"app-store"`: zero package signing errors, only the expected missing distribution certificate. `no_codesign:true` still archives successfully and removes any stale generated file. The env-var approach itself is still needed in spirit because flutter/flutter#113977 is open; only its scope changes. Xcode selection moves to a shared .github/actions/setup-xcode, defaulting to the newest Xcode on the image. The Fastfile no longer calls `select_xcode` — it cannot express "latest", since it resolves to /Applications/Xcode_<version>.app, and it was silently overriding the workflows' own choice with a pinned 26.2 that the xcode-27 image does not have. The two e2e jobs opt into 26.2 explicitly: they run on macos-15, whose default is Xcode 16.4, and their pinned simulator runtimes need 26.x. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`upload_dsyms_to_crashlytics` pointed `binary_path` at
ios/Pods/FirebaseCrashlytics/upload-symbols, which no longer exists now
that the sample app has no CocoaPods integration. Both iOS distribute
jobs archived, signed and exported their IPAs successfully and then died
here:
[!] Couldn't find file at path
'.../sample_app/ios/Pods/FirebaseCrashlytics/upload-symbols'
Under Swift Package Manager the binary lives in the firebase-ios-sdk
checkout instead. fastlane's own discovery only searches Pods/ and
Fabric.app, so the path is globbed and passed explicitly, with a clear
error if it moves again.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The comment claimed macos-15 defaults to Xcode 16.4 and therefore needs a 26.x toolchain. The image default is indeed 16.4, but setup-xcode's 'latest' resolves to the newest Xcode installed, which on macos-15 is 26.3 — so that was never the reason. The actual constraint is runtime alignment: macos-15 ships iOS simulator runtimes 18.5, 18.6, 26.0, 26.1 and 26.2, but no 26.3. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The per-package examples pinned deployment targets far below what Flutter
3.47 supports, so none of them could build. Raises iOS to 15.0 and macOS
to 12.0 — the values Flutter's own app template uses, and for macOS the
floor its generated FlutterMacOS.podspec declares, below which `pod
install` refuses to resolve.
Four Podfiles also declared a `RunnerTests` target that no project
defines, which failed `pod install` outright:
[!] Unable to find a target named `RunnerTests` in project
`Runner.xcodeproj`, did find `Runner`.
stream_chat_flutter's two Podfiles already had that stanza commented out,
which is why only those examples still built.
Every plugin these examples use is a Swift Package, so Flutter resolved
them all through SPM and then asked for CocoaPods to be removed by hand:
All plugins found for ios are Swift Packages, but your project still
has CocoaPods integration. [...] will need to be migrated to Swift
Package Manager manually.
Done here, so the six Podfiles are gone rather than fixed: `pod
deintegrate` on each project, Podfiles deleted, `Pods-Runner` includes
stripped from all twelve xcconfigs, and `Pods/Pods.xcodeproj` dropped
from the workspaces. Some of those includes were a hard `#include`, so
removing the Pods directory alone would have broken the build outright.
Building each example also applied Flutter 3.47's pending project
migrations — `@main`, `FlutterImplicitEngineDelegate`,
`UIApplicationSceneManifest`, and dropping the stale `MinimumOSVersion`
from AppFrameworkInfo.plist.
All seven configurations verified from a wiped build directory on Xcode
27.0 / Flutter 3.47.0 — no Podfile regenerated, no `pod install`, and no
migration warning: stream_chat, stream_chat_flutter,
stream_chat_flutter_core, stream_chat_localizations and
stream_chat_persistence on iOS, plus stream_chat_flutter and
stream_chat_persistence on macOS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
e253712 to
2f3b7b2
Compare
xsahil03x
left a comment
There was a problem hiding this comment.
Only looked at the workflows and the Fastfile — the pbxproj/Podfile churn I'm taking on trust from the seven local builds.
The signing fix is the right shape, and I convinced myself it actually holds: the Runner target's Release config declares neither CODE_SIGN_IDENTITY nor PROVISIONING_PROFILE_SPECIFIER (and this PR doesn't touch that), so the xcconfig values flow through; Profile shares Release.xcconfig as its base but overrides both at target level, so a profile build can't accidentally pick up the match profile. Generated.xcconfig has no signing keys either, so the include order is fine. Nice that select_xcode going away also takes the allure-lane exclusion list with it.
Thanks for dispatching the iOS e2e — that was the one path the green distribute_internal run didn't cover. Batch 0 is clean: no pod install, no Podfile regenerated, Xcode is set to 26.2.0 (17C52), 13 + 27 tests passed.
Dropping the pod cache also costs nothing — build (ios) came in at 6m45s here against 10–12m on recent runs.
Two comment fixes and one suggestion inline.
Unrelated to the code: build (ios) runs on every PR, so this puts larger-runner minutes on a public repo on the default path — you'd know better than me whether that's within budget.
| UI.user_error!('Could not find Crashlytics upload-symbols in build/ios/SourcePackages') if upload_symbols.nil? | ||
|
|
||
| upload_symbols_to_crashlytics( | ||
| dsym_path: dsym_zip, | ||
| gsp_path: "#{root_path}/ios/Runner/GoogleService-Info.plist", | ||
| binary_path: "#{root_path}/ios/Pods/FirebaseCrashlytics/upload-symbols" | ||
| binary_path: upload_symbols | ||
| ) |
There was a problem hiding this comment.
build/ios/SourcePackages is the Flutter tool's -clonedSourcePackagesDirPath, and the * absorbs whatever firebase-ios-sdk names its checkout — both can drift under a Flutter or Firebase bump. Because this lane runs before firebase_app_distribution / upload_to_testflight, a drift there hard-fails an already-built release over a symbol upload. dSYMs can be re-uploaded after the fact; a failed release costs a full rerun.
| UI.user_error!('Could not find Crashlytics upload-symbols in build/ios/SourcePackages') if upload_symbols.nil? | |
| upload_symbols_to_crashlytics( | |
| dsym_path: dsym_zip, | |
| gsp_path: "#{root_path}/ios/Runner/GoogleService-Info.plist", | |
| binary_path: "#{root_path}/ios/Pods/FirebaseCrashlytics/upload-symbols" | |
| binary_path: upload_symbols | |
| ) | |
| if upload_symbols.nil? | |
| UI.important('Could not find Crashlytics upload-symbols under build/ios/SourcePackages; skipping dSYM upload') | |
| next | |
| end | |
| upload_symbols_to_crashlytics( | |
| dsym_path: dsym_zip, | |
| gsp_path: "#{root_path}/ios/Runner/GoogleService-Info.plist", | |
| binary_path: upload_symbols | |
| ) |
There was a problem hiding this comment.
Agreed, and thanks — this was a real bug, not a style call. Confirmed the ordering you describe in all three release lanes: build_ipa → upload_dsyms_to_crashlytics → firebase_app_distribution / upload_to_testflight, so a glob miss aborted an already-built, already-signed release. The asymmetry you point at is the deciding argument: dSYMs can be uploaded after the fact, a failed release costs a full rebuild.
Applied in fecd043, with one deviation: UI.error instead of UI.important. Both are non-fatal, but the failure mode of skipping is silent — Crashlytics quietly goes unsymbolicated and nobody notices for months. Red in the log makes that harder to miss. Happy to switch to UI.important if you'd rather keep it a warning.
Also took your framing for the comment, since "outside our control" is the durable reason the branch has to exist at all:
# Both the SourcePackages directory and the checkout name are outside our
# control, so a miss is possible. This lane runs before the app is
# distributed: symbols can be uploaded later, a failed release cannot.Keeps the mechanism a future reader needs to avoid reintroducing the bug, drops the history and the point-in-time cache measurements — those belong in the pull request. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
upload_dsyms_to_crashlytics runs after build_ipa but before firebase_app_distribution and upload_to_testflight, so a missed glob aborted an already-built, signed release over a symbol upload. Both the SourcePackages directory and the firebase-ios-sdk checkout name can move under a Flutter or Firebase bump. Symbols can be uploaded after the fact; a failed release costs a full rebuild. Logs an error and skips instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🎯 Goal
Get every sample in the repo onto Xcode 27 —
sample_appand the five per-package example apps. While checking, CocoaPods turned out to be removable entirely, and the SPM signing failure from #2672 turned out to be fixable rather than permanent.🛠 Implementation details
FLUTTER_XCODE_CODE_SIGN_IDENTITY/..._PROVISIONING_PROFILE_SPECIFIERreach xcodebuild as command-line settings, so they land on every SPM package bundle too →Signing for "X" requires a development team(40+ targets). CocoaPods was immune only becausepodhelper.rbsetsCODE_SIGNING_ALLOWED = NOon pod resource bundles.build_ipanow writes both settings intoios/Flutter/Signing.xcconfig, which only the Runner target reads. SPM stays on; theDisable Swift Package Managersteps are gone.media_kit_videowas the last pod-only plugin and was dead weight — its desktop branch is gated on Windows/Linux, whichsample_apphas no runner directories for, so it always fell through toDefaultStreamVideoPlayer. Dropped it, deintegrated pods, deleted both Podfiles and thecocoapodsgem.upload-symbolsnow globbed from the SPM checkout instead ofios/Pods/.FlutterMacOS.podspecfloor, below whichpod installrefused to resolve.RunnerTeststarget no project defines. Targets raised, stanza dropped, CocoaPods deintegrated there as well — every plugin they use is already a Swift Package. Flutter's pending project migrations (@main,FlutterImplicitEngineDelegate,UIApplicationSceneManifest) came along with the builds.xcode-27image behind a new shared.github/actions/setup-xcode(one place for the version);select_xcodedropped from the Fastfile since it can't express "latest" and was overriding the workflows with a pinned 26.2 the image lacks; e2e jobs pin 26.2 explicitly; pod cache action deleted.☑️ Verification
distribute_internalis green on this branch — run 34455350823. Both iOS jobs signed, symbolicated and shipped (Firebase App Distribution +Successfully uploaded package to App Store Connect) with zero signing errors and zeropod install. Locallysample_appalso builds and runs on an iOS 27 simulator and macOS 26.6.2, and all seven example-app configurations build from a wipedbuild/with no Podfile regenerated and nopod install. Note CI never builds the examples — no workflow references them andmelos run analyzeskips them — so those seven builds are their only coverage.☑️Contributor Checklist
General
☑️Reviewer Checklist
🤖 Generated with Claude Code
Summary by CodeRabbit
Build & Platform Updates
Video Playback
Release Engineering