Skip to content

ci: build every iOS and macOS app with Swift Package Manager only - #18852

Merged
Lyokone merged 10 commits into
mainfrom
ci/spm-only-apple-builds
Oct 22, 2026
Merged

Lyokone merged 10 commits into
mainfrom
ci/spm-only-apple-builds

Conversation

@Lyokone

@Lyokone Lyokone commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Description

Moves every iOS and macOS build in the repository, in CI and locally, to Swift Package Manager only. The CocoaPods trunk goes read-only at the end of 2026, and Firebase Apple SDK 13 is SPM-only, so the CocoaPods jobs were still testing 12.x.

Before: iOS e2e mostly used SPM, but auth, crashlytics, functions and performance used CocoaPods, and FDC was effectively CocoaPods too (its pubspec turned SPM off). Every macOS e2e job and both smoke test jobs used CocoaPods on purpose. All 35 example and tests/ Apple projects committed a Podfile, so a local flutter run built with CocoaPods or a mix of both.

After: no Podfile and no CocoaPods opt-out remain anywhere.

  • Example and tests/ apps: CocoaPods is removed with pod deintegrate, along with the Podfile, the Pods workspace ref, the xcconfig includes and stale header search paths. Flutter's --config-only then added the SPM integration (and its usual Xcode project migrations), so local builds no longer rewrite the projects. Every pubspec pins enable-swift-package-manager: true.
  • firebase_auth example: google_sign_in couldn't resolve under SPM: every GoogleSignIn-iOS release needs App Check 11, while Firebase SDK 13 needs 12. [App Check] Add SPM AppCheckCore 12.x support google/GoogleSignIn-iOS#626 is merged but not released yet. flutter_facebook_auth's macOS implementation has no Package.swift. The example now signs in through FirebaseAuth instead:
    • Google uses signInWithProvider on Android and iOS and signInWithPopup on web, and is hidden on Windows.
    • Facebook is web-only, because Firebase rejects Facebook through the generic provider flow on Apple and Android.
    • google_sign_in, google_sign_in_dartio and flutter_facebook_auth are removed.
  • firebase_crashlytics example: the build phases call Crashlytics/run and upload-symbols from the SPM checkout instead of $PODS_ROOT. That checkout is ${BUILD_DIR%/Build/*}/SourcePackages, falling back to build/<platform>/SourcePackages for archives. macOS keeps the Debug / no-dSYM guard that pod install used to inject.
  • firebase_data_connect example: drops its SPM opt-out and an unused google_sign_in dependency.
  • tests/ smoke app: drops the CocoaPods-generated Crashlytics upload-symbols phase.
  • firebase_messaging (macOS): the bundled PrivacyInfo.xcprivacy was a relative symlink into ios/. Under SPM, Xcode reads path-dependency plugins through Flutter's ephemeral package symlink, so the link didn't resolve and every macOS SPM build that included messaging failed. It is now a real copy, and swift-integration's workaround that dropped messaging from its macOS build is removed.
  • CI:
    • reusable_e2e_ios.yaml and reusable_e2e_macos.yaml lose the ios-spm input (and the short-lived macos-spm), the "Disable Swift Package Manager" steps and the Pods caches.
    • functions, performance, FDC, smoke and pipeline now build with SPM, and the CI-time pod deintegrate steps are gone.
    • Every Apple build fails if it runs pod install, so a silent CocoaPods fallback can't pass.
    • Smoke and FDC get the same one-shot retry on Xcode's intermittent "Could not resolve package dependencies" race as the reusable jobs.
  • CONTRIBUTING.md documents the SPM-only setup.

The plugins' podspecs are unchanged, so apps that use FlutterFire with CocoaPods keep working.

Testing

  • Local arm64 debug builds with Flutter 3.44.6 and Xcode 27.1, with no pod install in any of them:
    • iOS: functions, performance, data_connect, auth, crashlytics and tests/.
    • macOS: messaging, functions, core, storage, auth, crashlytics and tests/.
  • tests/ macOS failed on the messaging privacy-manifest symlink before the fix and passes after it.
  • The Crashlytics iOS example fails under SPM with the old $PODS_ROOT script and passes with the new one. The new scripts were also checked against simulated Xcode, flutter build and archive layouts.
  • actionlint and shellcheck are clean apart from the existing xcode-27 runner label and all_plugins.yaml notes. flutter_plugin_tools format is clean.
  • Not yet run: the e2e tests in CI. This is the first CI run of the macOS e2e jobs under SPM.

Notes for reviewers

  • The pubspec flutter: config: key needs Flutter 3.35 or newer. The examples still declare flutter: '>=3.27.0', so older tools reject the pubspec. CI uses stable.
  • Smoke and FDC lose their Pods caches, and nothing caches SPM yet (the iOS jobs already on SPM didn't either).

Related Issues

None filed.

Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • My PR includes unit or integration tests for all changed/updated/fixed behaviors (See Contributor Guide). CI/build-only change; the existing e2e suites cover it.
  • All existing and new tests are passing. (Pending CI.)
  • I updated/added relevant documentation (doc comments with ///).
  • The analyzer (melos run analyze) does not report any problems on my PR. (dart analyze is clean on the changed Dart files; full analyze pending CI.)
  • I read and followed the Flutter Style Guide.
  • I signed the CLA.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

  • Yes, this is a breaking change.
  • No, this is not a breaking change.

Every example except firebase_auth and firebase_crashlytics, and the
tests/ smoke app, now builds with Swift Package Manager only:

- run `pod deintegrate`, delete the Podfile and drop the Pods
  workspace ref, xcconfig includes and stale Pods header search paths
- let `flutter build <platform> --config-only` add the Swift Package
  Manager integration (and Flutter's other Xcode project migrations), so
  local builds no longer rewrite the projects
- pin `enable-swift-package-manager: true` in each pubspec
- drop the CocoaPods-only Crashlytics upload-symbols phase from tests/
- firebase_data_connect: drop the SPM opt-out and the unused
  google_sign_in dependency that could not resolve under SPM

firebase_auth (google_sign_in) and firebase_crashlytics (PODS_ROOT build
scripts) stay on CocoaPods until they can resolve under SPM.
- reusable macOS e2e: SPM by default, with a `macos-spm` opt-out like
  the iOS job's `ios-spm`; firebase_auth and firebase_crashlytics keep
  CocoaPods on both platforms
- cloud_functions and firebase_performance iOS rejoin SPM: the Xcode
  26.2 pin their opt-out blamed is gone
- firebase_data_connect iOS and the smoke app's iOS/macOS jobs switch
  from CocoaPods to SPM and drop their Pods caches
- drop the CI-time `pod deintegrate` steps now that the examples commit
  no Podfile
- fail every SPM build that still runs `pod install`, so a silent
  CocoaPods fallback can't pass
- document the SPM-only setup in CONTRIBUTING.md
…ckage Manager

The macOS package's privacy manifest was a relative symlink into the iOS
sources. Under SPM, Xcode reads a path-dependency plugin through Flutter's
ephemeral package symlink, where that relative target no longer resolves,
so any app depending on firebase_messaging from this repository (the
tests/ smoke app, swift-integration's macOS build) failed with
"PrivacyInfo.xcprivacy couldn't be opened". Copy the file instead, and
drop swift-integration's workaround that removed firebase_messaging
from its macOS build.
- pin enable-swift-package-manager: false in the firebase_auth and
  firebase_crashlytics examples, so a local build is plain CocoaPods
  rather than a broken hybrid
- retry the smoke and firebase_data_connect builds once on the SPM
  package resolution race, like the reusable jobs
- stream the macOS build log instead of printing it afterwards
google_sign_in could not resolve under SPM (every GoogleSignIn-iOS release
needs App Check 11, Firebase Apple SDK 13 needs 12), and
flutter_facebook_auth's macOS implementation ships no Package.swift.
Sign in through FirebaseAuth itself instead and drop google_sign_in,
google_sign_in_dartio and flutter_facebook_auth:

- Google: signInWithProvider on Android and iOS, signInWithPopup on web;
  hidden on Windows, which has no provider flow (macOS already shows
  only Apple)
- Facebook: web only, as Firebase rejects it through the generic
  provider flow on Apple and Android
- remove the Facebook keys and URL scheme from the iOS Info.plist

Then remove CocoaPods from the iOS and macOS projects like the other
examples and pin enable-swift-package-manager: true.
The example's build phases ran Crashlytics' run and upload-symbols tools
from $PODS_ROOT, which does not exist under SPM. Call them from the
firebase-ios-sdk checkout SPM makes instead: next to the build products
(${BUILD_DIR%/Build/*}/SourcePackages, as Firebase documents, which is
also where `flutter build` clones it), falling back to
build/<platform>/SourcePackages for archives, where BUILD_DIR points into
DerivedData.

On macOS, keep the guard CocoaPods used to add at `pod install` time
(crashlytics_add_upload_symbols): skip Debug builds and builds without
a dSYM instead of uploading on every build.

Then remove CocoaPods from both projects like the other examples and pin
enable-swift-package-manager: true.
Every example now builds with Swift Package Manager, so remove the
ios-spm/macos-spm inputs, the 'Disable Swift Package Manager' steps and
the Pods caches, and always fail a build that runs pod install.
@gemini-code-assist

Copy link
Copy Markdown
Contributor
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Flutter adds a plugin's own Swift package to its example app's Xcode
project as a local override, at the plugin's real path. When Xcode
resolves that override instead of the copy in Flutter's ephemeral
package symlink farm, the plugin's path: "../firebase_core" and
"../FlutterFramework" dependencies point next to the real package and
resolution fails ("... doesn't exist in file system"). The CI's default
Xcode 27.0 did this for 4 of 11 macOS examples and the Firestore
pipeline example, twice in a row each.

Link those sibling dependencies into the plugin's platform directory,
pointing at the farm Flutter generates, before every example build.
Locally, fresh resolutions of the storage macOS and pipeline iOS examples
failed 7 of 10 times without the links and 0 of 12 with them.
The test added in #18797 signs in anonymously, which persists the user to
the keychain. The unsigned CI macOS app cannot write to it
(errSecMissingEntitlement, -34018), so the e2e-auth macOS job has failed
on main since. Skip it on macOS like the file's other sign-in tests; the
signed-out variant still runs there.
@Lyokone
Lyokone marked this pull request as ready for review October 22, 2026 11:40

@SelaseKay SelaseKay left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The auth example's Google button on Android now calls signInWithProvider, and example/android/app/src/main/AndroidManifest.xml still sets android:taskAffinity="". That is the combination docs/auth/federated-auth.md warns about: the Chrome Custom Tab closes when the user switches apps, and coming back fails with web-context-already-presented. Let's remove android:taskAffinity="" from that manifest.

The example's Google button now uses signInWithProvider on Android, like
the GitHub, Microsoft, Twitter and Yahoo ones. With android:taskAffinity=""
the Chrome Custom Tab closes when the user switches apps and returning
fails with web-context-already-presented, as docs/auth/federated-auth.md
warns.
@Lyokone
Lyokone merged commit a98a82d into main Oct 22, 2026
128 of 132 checks passed
@Lyokone
Lyokone deleted the ci/spm-only-apple-builds branch October 22, 2026 15:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants