Skip to content

feat(ios): add SPM dependency resolution support alongside CocoaPods#8933

Open
jsnavarroc wants to merge 40 commits into
invertase:mainfrom
jsnavarroc:main
Open

feat(ios): add SPM dependency resolution support alongside CocoaPods#8933
jsnavarroc wants to merge 40 commits into
invertase:mainfrom
jsnavarroc:main

Conversation

@jsnavarroc

@jsnavarroc jsnavarroc commented Mar 17, 2026

Copy link
Copy Markdown

Summary

  • Add dual SPM/CocoaPods dependency resolution for Firebase iOS SDK via a centralized firebase_dependency() helper (packages/app/firebase_spm.rb)
  • When React Native >= 0.75 is detected, Firebase dependencies are resolved via Swift Package Manager (spm_dependency). For older versions or when explicitly disabled ($RNFirebaseDisableSPM = true), CocoaPods is used as fallback.
  • Solves Xcode 26 compilation errors caused by explicit modules not finding Firebase internal modules (FirebaseCoreInternal, FirebaseSharedSwift) when using CocoaPods

Changes

  • packages/app/firebase_spm.rb — New helper with firebase_dependency() function that auto-detects SPM support
  • packages/app/package.json — Added firebaseSpmUrl field as single source of truth
  • 16 podspecs — Updated to use firebase_dependency() instead of direct s.dependency
  • 43 native iOS files — Added #if __has_include guards for dual SPM/CocoaPods imports
  • CI matrix — Extended E2E workflow with dep-resolution: ['spm', 'cocoapods'] dimension (4 job combinations)
  • Unit tests — Added Ruby Minitest suite for firebase_spm.rb logic
  • Documentation — Added docs/ios-spm.md with architecture, integration guides, and troubleshooting

How it works

# Each podspec calls:
firebase_dependency(s, version, ['FirebaseAuth'], 'Firebase/Auth')

# Internally decides:
# - SPM path:      spm_dependency(spec, url: ..., products: ['FirebaseAuth'])
# - CocoaPods path: spec.dependency 'Firebase/Auth', version

Decision logic:

  1. Is spm_dependency() defined? (RN >= 0.75 injects it) → YES → use SPM
  2. Is $RNFirebaseDisableSPM set in Podfile? → YES → force CocoaPods
  3. Neither available → fall back to CocoaPods

User-facing configuration

SPM mode (default for RN >= 0.75):

# ios/Podfile
linkage = 'dynamic'
use_frameworks! :linkage => linkage.to_sym

CocoaPods mode (legacy/opt-out):

# ios/Podfile
$RNFirebaseDisableSPM = true
linkage = 'static'
use_frameworks! :linkage => linkage.to_sym

Xcode 26 workaround (both modes):

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['SWIFT_ENABLE_EXPLICIT_MODULES'] = 'NO'
    end
  end
end

Test plan

  • Ruby unit tests pass (packages/app/__tests__/firebase_spm_test.rb)
  • CI: Code Quality Checks pass (clang-format, linting)
  • CI: E2E iOS debug + SPM passes
  • CI: E2E iOS debug + CocoaPods passes
  • CI: E2E iOS release + SPM passes
  • CI: E2E iOS release + CocoaPods passes
  • $RNFirebaseDisableSPM = true correctly forces CocoaPods
  • Log messages indicate which resolution mode is active

related issue: #9010


Note

Medium Risk
Medium risk because it changes iOS dependency/linkage and native import behavior across many modules, which can break builds in certain Xcode/React Native configurations despite added CI coverage.

Overview
Introduces a centralized firebase_dependency() helper (packages/app/firebase_spm.rb) that switches RNFirebase iOS Firebase dependencies between SPM (RN >= 0.75 by default) and CocoaPods (fallback or $RNFirebaseDisableSPM), with the SPM repo URL sourced from packages/app/package.json.

Updates all affected RNFirebase module podspecs to use the helper (including special-casing Analytics’ SPM vs CocoaPods behavior), adjusts numerous iOS sources to compile under both header layouts via __has_include/module imports, and extends Crashlytics symbol upload scripting to find the SPM checkout.

Expands iOS E2E CI to run a matrix over spm/cocoapods × debug/release (including mode-specific Podfile edits and cache keys), adds Ruby unit tests for the helper and runs them in the Jest workflow, and adds new SPM documentation plus a local SPM verification screen.

Reviewed by Cursor Bugbot for commit 496d97c. Bugbot is set up for automated code reviews on this repo. Configure here.

@CLAassistant

CLAassistant commented Mar 17, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
2 out of 3 committers have signed the CLA.

✅ jsnavarroc
✅ russellwheatley
❌ Johan Navarro


Johan Navarro seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@vercel

vercel Bot commented Mar 17, 2026

Copy link
Copy Markdown

@jsnavarroc is attempting to deploy a commit to the Invertase Team on Vercel.

A member of the Team first needs to authorize it.

Add dual SPM/CocoaPods dependency resolution for Firebase iOS SDK.

When React Native >= 0.75 is detected, Firebase dependencies are resolved
via Swift Package Manager (spm_dependency). For older versions or when
explicitly disabled ($RNFirebaseDisableSPM = true), CocoaPods is used.

Changes:
- Add firebase_spm.rb helper with firebase_dependency() function
- Add firebaseSpmUrl to packages/app/package.json (single source of truth)
- Update all 16 podspecs to use firebase_dependency()
- Add #if __has_include guards in 43 native iOS files for dual imports
- Add CI matrix (spm × cocoapods × debug × release) in E2E workflow
- Add Ruby unit tests for firebase_spm.rb
- Add documentation at docs/ios-spm.md
jsnavarroc and others added 2 commits March 18, 2026 11:55
…dSupport is true

When $RNFirebaseAnalyticsWithoutAdIdSupport = true with SPM enabled,
FirebaseAnalytics pulls in GoogleAppMeasurement which contains APMETaskManager
and APMMeasurement cross-references. These cause linker errors when
FirebasePerformance is not installed.

Switch to FirebaseAnalyticsCore (-> GoogleAppMeasurementCore) in that case,
which has no IDFA and no APM symbols. CocoaPods path is unchanged.

docs: add Section 8 with 5 real integration bugs found during tvOS Xcode 26
migration and their solutions
fix(analytics): use FirebaseAnalyticsCore when WithoutAdIdSupport + SPM
@jsnavarroc

jsnavarroc commented Mar 18, 2026

Copy link
Copy Markdown
Author

Additional fix included: FirebaseAnalyticsCore when SPM + $RNFirebaseAnalyticsWithoutAdIdSupport = true

While integrating this PR in a tvOS app (React Native tvOS 0.77, Xcode 26), we encountered a linker error that is only triggered when all three conditions are true simultaneously:

  1. SPM dependency resolution is active (this PR)
  2. $RNFirebaseAnalyticsWithoutAdIdSupport = true in Podfile
  3. FirebasePerformance is not installed

Linker error

Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_APMETaskManager"
  "_OBJC_CLASS_$_APMMeasurement"

Root cause

The FirebaseAnalytics SPM product resolves to GoogleAppMeasurement, which contains cross-references to APMETaskManager and APMMeasurement (Firebase Performance classes). When FirebasePerformance is not in the project, those symbols are missing at link time.

The fix: when SPM + WithoutAdIdSupport = true, use FirebaseAnalyticsCore instead — it resolves to GoogleAppMeasurementCore (no IDFA, no APM dependencies).

Fix applied in RNFBAnalytics.podspec

if defined?(spm_dependency) && !defined?($RNFirebaseDisableSPM) &&
   defined?($RNFirebaseAnalyticsWithoutAdIdSupport) && $RNFirebaseAnalyticsWithoutAdIdSupport
  firebase_dependency(s, firebase_sdk_version, ['FirebaseAnalyticsCore'], 'FirebaseAnalytics/Core')
else
  firebase_dependency(s, firebase_sdk_version, ['FirebaseAnalytics'], 'FirebaseAnalytics/Core')
end

This change is fully backwards compatible — all existing paths (CocoaPods, SPM without the flag, SPM with IDFA) are unchanged.

This fix is already included in the current head of this PR. Happy to extract it into a separate PR if preferred.


Context: why SPM matters for React Native in 2026

This article is highly relevant for the community — it covers the broader roadmap and real-world pain points of migrating React Native apps to SPM, including the Xcode 26 requirement and Firebase-specific issues:

📖 React Native — Roadmap to Swift Package Manager 2026

@jsnavarroc

Copy link
Copy Markdown
Author

Hey @mikehardy — could you approve the workflows to run on this PR when you get a chance?

The CI checks are blocked waiting for maintainer approval. Happy to address any feedback once they run.

Thanks!

@mikehardy mikehardy left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Wow! This is pretty amazing. Thank you for proposing this - just finished first pass review and while I left comments all over the place I hope none of that gives the feeling that this isn't amazing, and that we won't merge SPM support, it is something this repository obviously needs. So again, thank you

But then of course there are all the comments with some specific questions, some pings out to a firebase-ios-sdk maintainer (hi Paul 👋 ) that I collaborate with on occasion, and some notes to myself regarding testing

Comment thread .github/workflows/tests_e2e_ios.yml Outdated
#import <Firebase/Firebase.h>
#else
@import FirebaseCore;
@import FirebaseAnalytics;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Taking note of your comment here on the FirebasePerformance symbols missing at link time if ad ids are disabled does this FirebaseAnalytics import still work here in the FirebaseAnalyticsCore dependency case? #8933 (comment)

@jsnavarroc jsnavarroc Apr 22, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good question. Yes, @import FirebaseAnalytics still works when the dependency is FirebaseAnalyticsCore. They share the same Clang module and headers, the difference is only at link time: FirebaseAnalyticsCore links GoogleAppMeasurementCore (no IDFA, no APM symbols) while FirebaseAnalytics links GoogleAppMeasurement (includes APMETaskManager, APMMeasurement). The import resolves the same API surface in both cases.

Comment thread packages/analytics/RNFBAnalytics.podspec Outdated
s.frameworks = 'AdSupport'
end

# GoogleAdsOnDeviceConversion (CocoaPods only, not available in firebase-ios-sdk SPM)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is there some documentation on how to access on-device conversion in the SPM case? This is surprising to me as I thought on-device conversion was one of the newer features of firebase-ios-sdk which creates the expectation in me that it should be available there somehow ? Perhaps just built in to core SPM dep I'm not sure

@jsnavarroc jsnavarroc Apr 22, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

GoogleAdsOnDeviceConversion is a static xcframework distributed separately from firebase-ios-sdk. It is NOT available as an SPM product in Package.swift. When using SPM (dynamic linkage), it causes duplicate symbol errors.

In the latest commit I've added:

  1. A clear comment explaining the limitation
  2. A runtime warning when the user enables it in SPM mode
  3. Documentation pointing users to set $RNFirebaseDisableSPM = true if they need on-device conversion.

If firebase-ios-sdk adds it as an SPM product in the future, we can remove this restriction.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is something we need to figure out - it must be possible as I'm seeing reports of regular (native) integrations of firebase-ios-sdk as well as Flutter folks using ODC / On Device Conversion) - sometimes with some difficult for example firebase/firebase-ios-sdk#15916 but with eventual success

@russellwheatley russellwheatley Jul 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

GoogleAdsOnDeviceConversion isn't part of firebase-ios-sdk's own Package.swift (checked directly, no references at all), but Google publishes it as its own standalone SPM package: googleads/google-ads-on-device-conversion-ios-sdk. It has its own Package.swift with a GoogleAdsOnDeviceConversion library product wrapping a prebuilt xcframework binary target.

RN's SPMManager (node_modules/react-native/scripts/cocoapods/spm.rb) keys dependencies by pod target and package URL in a list, so a second, independent spm_dependency() call on the same pod target resolves an unrelated SPM package just fine which is the supported pattern.

Fixed in 1c2fee7 - added a second spm_dependency() call for this package when the SPM path is active, replacing the warn-and-refuse behavior. Noted the -ObjC/-lc++ linker flag caveat from firebase-ios-sdk#15916 in the comment in case anyone hits it (that report was about an indirect/wrapper package scenario, not our direct call, but worth flagging for troubleshooting).

Comment on lines +18 to +21
#if __has_include(<Firebase/Firebase.h>)
#import <Firebase/Firebase.h>
#import <FirebaseAppCheck/FIRAppCheck.h>
#elif __has_include(<FirebaseAppCheck/FirebaseAppCheck.h>)
#import <FirebaseAppCheck/FirebaseAppCheck.h>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

<Firebase/Firebase.h> will always be found in the CocoaPods case won't it? It's the most fundamental header if I understand correctly. Does it transitively include <FirebaseAppCheck/FIRAppCheck.h> such that the explicit import is no longer required then (or maybe was never required?). Surprising this compiles as I think that preprocessor branch is likely the only __has_include branch that will ever be taken, and it makes me think the #elif __has_include(<FirebaseAppCheck/FirebaseAppCheck.h>) branch may not even be needed, I can't see how <Firebase/Firebase.h> won't be found

@jsnavarroc jsnavarroc Apr 22, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

You're right that <Firebase/Firebase.h> will always be found in CocoaPods since it's the umbrella header. The #elif branch covers an edge case where someone installs only individual Firebase pods without the umbrella Firebase/Firebase pod. In practice, since RNFB always depends on RNFBApp which brings FirebaseCore, the first branch is effectively always taken in CocoaPods.

The three-branch structure is: CocoaPods umbrella, then CocoaPods individual pods, then SPM (@import). I can simplify to just #if/#else (CocoaPods umbrella vs SPM @import) if you prefer, let me know.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@mikehardy, for direct firebase-ios-sdk usage, the recommendation is to use the individual pods (pod 'FirebaseAppCheck' (no /)) rather than the umbrella pod (pod 'Firebase/AppCheck'). In any case, the new versions of Firebase.podspec will continue to be released with the other pods up through October 2026.

Comment thread packages/app/README.md Outdated
Comment thread packages/app/firebase_spm.rb
Comment thread packages/app/firebase_spm.rb
Comment thread packages/analytics/RNFBAnalytics.podspec
Comment thread DOCUMENTACION_SPM_IMPLEMENTACION.md Outdated
@mikehardy mikehardy added Workflow: Waiting for User Response Blocked waiting for user response. Workflow: Needs Review Pending feedback or review from a maintainer. and removed Needs Attention labels Mar 19, 2026
@mikehardy

Copy link
Copy Markdown
Collaborator

Hey @jsnavarroc 👋 just a gentle ping on this - are you interested in / have time to work on moving this forward? Happy to collaborate, and it's a pretty important feature so I'm very interested personally. Curious for your thoughts

@mikehardy mikehardy added Workflow: Needs Second Review Waiting on a second review before merge Workflow: Waiting for User Response Blocked waiting for user response. Workflow: Needs Review Pending feedback or review from a maintainer. and removed Workflow: Waiting for User Response Blocked waiting for user response. Workflow: Needs Review Pending feedback or review from a maintainer. Workflow: Needs Second Review Waiting on a second review before merge labels Mar 31, 2026
@jsnavarroc

jsnavarroc commented Apr 22, 2026

Copy link
Copy Markdown
Author

Hey @mikehardy! Yes, absolutely, I'm actively working on this and just pushed a new commit addressing all the review comments. Sorry for the delay.

Changes in the latest commit

  1. Cache key order: Reordered per your suggestion (variable interpolations first)
  2. Analytics podspec comment inconsistency: Fixed, it's FirebasePerformance (APM symbols), not RemoteConfig
  3. GoogleAdsOnDeviceConversion: Added clear documentation about SPM incompatibility + runtime warning when user tries to enable it in SPM mode
  4. AppCheckModule.m spacing: Reverted all unrelated spacing changes, kept only the #if __has_include import block
  5. .npmignore: Added clarifying comment about the !ios/RNFBApp/RNFBVersion.m inclusion and the lack of a files array in package.json
  6. RNFBML.podspec: Removed old commented-out s.dependency and raise lines
  7. firebase_spm.rb: Improved static linkage comment with upstream context, added monorepo/pnpm path resolution note
  8. README: Added Expo section, reframed dynamic/static in terms of pre-built RN core, added monorepo/pnpm notes
  9. ios_config.sh: Replaced find with known deterministic path for SPM upload-symbols
  10. DOCUMENTACION_SPM_IMPLEMENTACION.md: Deleted (was a Spanish duplicate of docs/ios-spm.md)

Ask

If you or anyone on the team has bandwidth to test this branch on different devices/platforms (iOS, tvOS, macCatalyst) and with different configurations (SPM vs CocoaPods, dynamic vs static), that would be incredibly valuable. I've verified it on iOS 26 simulator and tvOS 26 (Apple TV) but broader coverage would help catch edge cases before merge.

I'll reply to each individual review comment below with details.

FirebaseInstallations is a transitive dependency of FirebaseCore.
With SPM dynamic linking, transitive frameworks are not embedded
automatically — they must be declared explicitly as SPM products.

Without this, dyld crashes at launch with:
'symbol not found in flat namespace _FIRInstallationIDDidChangeNotification'

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 496d97c. Configure here.

Comment thread packages/analytics/RNFBAnalytics.podspec
@paulb777

Copy link
Copy Markdown
Contributor

Great to see the progress in this PR! I'm cc'ing @ncooke3, who is now a better contact than me for the firebase-ios-sdk questions in the comments.

@jsnavarroc

jsnavarroc commented Apr 23, 2026

Copy link
Copy Markdown
Author

Heads up: tvOS + Xcode 26 hybrid SPM/CocoaPods edge case worth documenting

While integrating this PR in a tvOS React Native project (hybrid CocoaPods + SPM resolution, Xcode 26, RN 0.77 with react-native-tvos), I ran into a subtle TestFlight-only crash that took considerable time to diagnose. Sharing here so maintainers can decide if it's worth adding a warning or a note in the docs.

Symptom

  • App launches fine on tvOS simulator ✅
  • App launches fine when installed directly from Xcode onto a real Apple TV (WiFi pairing or USB-C) ✅
  • App crashes immediately at launch (<200ms, pre-main()) when the same archive is uploaded via Fastlane and installed from TestFlight ❌

No formal crash log is generated, ReportCrash logs Failed to create bundle record because the process dies too early. The only signal in the system log (from Console.app connected to the device) is:

PineBoard  [app<com.example.myapp>:738] Now flagged as pending exit for reason: launch failed
PineBoard  [app<com.example.myapp>:738] Process exited:
  <RBSProcessExitContext| specific, status:<RBSProcessExitStatus| domain:dyld(6) code:0>>.

Root cause

The combination that triggers it:

  1. Firebase resolved via SPM (source packages, statically linked into the main app binary)
  2. @react-native-firebase/* frameworks compiled as dynamic frameworks with -undefined dynamic_lookup (necessary in hybrid setup to avoid duplicate Firebase class registrations, as documented in other threads)
  3. Release configuration with default stripping settings (DEAD_CODE_STRIPPING=YES, STRIP_SWIFT_SYMBOLS=YES, etc.)

The Release + TestFlight pipeline strips Firebase symbols from the main binary's dynamic symbol table because the static analyzer sees them as "unused", nothing in the binary statically references them, RNFB frameworks resolve them at runtime via flat-namespace dynamic lookup. When dyld tries to resolve them on device after TestFlight processing, they're gone. Local Xcode installs don't exhibit this because development builds don't apply the same aggressive stripping.

Diagnostic evidence

Before fix (binary that crashed in TestFlight):

  • Main app binary size: 3.3 MB
  • nm -g <binary> | grep "FIR" | wc -l0
  • nm -g <binary> | grep "InstallationIDDidChange" → nothing

After fix (binary that works in TestFlight):

  • Binary size: 6.0 MB (+80%)
  • nm -g <binary> | grep "FIR" | wc -l692
  • nm -g <binary> | grep "InstallationIDDidChange"S _FIRInstallationIDDidChangeNotification

Workaround

Anti-stripping settings on the main app target's Release configuration + exporting static symbols to the dynamic symbol table, added via post_install hook in the integrator's Podfile:

main_target.build_configurations.each do |cfg|
  next unless cfg.name == 'Release'
  cfg.build_settings['STRIP_SWIFT_SYMBOLS'] = 'NO'
  cfg.build_settings['DEAD_CODE_STRIPPING'] = 'NO'
  cfg.build_settings['STRIP_INSTALLED_PRODUCT'] = 'NO'
  cfg.build_settings['COPY_PHASE_STRIP'] = 'NO'
  cfg.build_settings['DEPLOYMENT_POSTPROCESSING'] = 'NO'
  ldflags = Array(cfg.build_settings['OTHER_LDFLAGS'] || ['$(inherited)'])
  ldflags << '-Wl,-export_dynamic' unless ldflags.include?('-Wl,-export_dynamic')
  cfg.build_settings['OTHER_LDFLAGS'] = ldflags
end

This belongs in the integrator's Podfile, not in the library, because it's specific to the hybrid linkage strategy and tvOS, and would be intrusive for iOS projects that don't need it (binary size doubles, Release optimizations disabled).

Suggestion

Since this is very hard to diagnose without the crashlog (which doesn't get generated) and only manifests after TestFlight upload (long iteration cycle), it might be worth considering one of:

  1. A non-blocking warning during pod install when the risky combination is detected (platform: tvos + SPM active + main target missing anti-stripping in Release), pointing to the fix.
  2. A troubleshooting section in the README / docs/ios-spm.md documenting the symptom and the Podfile snippet.

Happy to open a separate PR with either approach if maintainers think it's worth it, fully understand if you'd rather keep this PR focused and tackle it separately later. Flagging it here so it doesn't get lost.

Context: reproducible on my setup (Apple TV 4K, tvOS 26, Xcode 26.3, use_frameworks! :linkage => :static, Firebase iOS SDK 12.x via SPM). Others on the same configuration may hit it too.

cc @ncooke3 (per @paulb777's earlier comment pointing to you for firebase-ios-sdk questions), sharing in case this stripping interaction is relevant on the Firebase SDK side.

@ncooke3

ncooke3 commented Apr 23, 2026

Copy link
Copy Markdown

Hi @jsnavarroc, nice testing & investigation! If you didn't consider it, adding the -ObjC linker flag could possibly be an additional path that may (or may not) work, though it's not as precise as the workaround you documented. I'm unsure if it handles the risk of duplicate symbols.

In any case, I'll defer to @mikehardy here, but your suggestions sound reasonable.

Add an RNFB SPM post-install patch that injects an app-target build
phase for Firebase SPM dynamic frameworks. The phase copies frameworks
built under Xcode's PackageFrameworks directory into the app Frameworks
folder when they were not already embedded by CocoaPods.

This fixes release launches where RNFBStorage links FirebaseStorage,
FirebaseStorage links FirebaseAppCheckInterop, but the app bundle does
not contain FirebaseAppCheckInterop.framework. The fix keeps Storage
declaring only the public FirebaseStorage product and avoids requiring
consumers to install App Check or add a Podfile workaround.

Also regenerates the iOS test project so the new embed phase is present.
@russellwheatley

russellwheatley commented Jul 14, 2026

Copy link
Copy Markdown
Member

I pushed a follow-up fix for the Release+SPM launch failure here:

jsnavarroc@e4595a5

What was happening:

  • The app was dying at launch with dyld before Jet/Detox could run integration tests.
  • RNFBStorage.framework links Firebase's SPM-built interop frameworks, especially FirebaseAppCheckInterop.framework.
  • Xcode was building those frameworks under Build/Products/.../PackageFrameworks, but CocoaPods' [CP] Embed Pods Frameworks phase only copied CocoaPods-built frameworks into testing.app/Frameworks.
  • So release launch failed because testing.app/Frameworks/FirebaseAppCheckInterop.framework was missing.

Instead, packages/app/firebase_spm.rb now patches the React Native SPM post-install path to add an app-target phase, [RNFB] Embed Firebase SPM Frameworks, which copies missing SPM-built dynamic frameworks from $(BUILT_PRODUCTS_DIR)/PackageFrameworks into the app bundle after CocoaPods has embedded its frameworks.

@mikehardy mikehardy left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

still reading through this - got to the Obj-C helper stuff - that's a pretty big change and I still need to consider it. I wonder if converting to swift internally here in react-native-firebase would simplify things at all - I'm aware of the need for Objective-C in order to complete the journey to native from TurboModules codegen so I'm not sure it would be simplifying at all but I was casting about for any idea to avoid need for one more indirection step of "helper" files to keep our Obj-C "firebase-clean" in the SPM environment

Comment thread .github/workflows/scripts/simulator-logging.sh Outdated
"iteration": iterationArray,
"buildmode": buildmode
"buildmode": buildmode,
"dep-resolution": depResolution

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

great use of the matrix capability

Comment thread docs/ios-spm.mdx Outdated
Comment thread docs/ios-spm.mdx Outdated
Comment thread docs/ios-spm.mdx Outdated
s.frameworks = 'AdSupport'
end

# GoogleAdsOnDeviceConversion (CocoaPods only, not available in firebase-ios-sdk SPM)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is something we need to figure out - it must be possible as I'm seeing reports of regular (native) integrations of firebase-ios-sdk as well as Flutter folks using ODC / On Device Conversion) - sometimes with some difficult for example firebase/firebase-ios-sdk#15916 but with eventual success

Comment thread packages/analytics/RNFBAnalytics.podspec
Comment thread packages/app/firebase_spm.rb
Replace the explicit rnfirebase_add_spm_embed_phase Podfile call with a
CocoaPods-level hook (Pod::Installer#run_podfile_post_install_hooks) so
Firebase's SPM-built dynamic frameworks are embedded automatically on
every pod install, with no consumer Podfile edits and no dependency on
React Native's private SPM internals.
@jsnavarroc

jsnavarroc commented Jul 14, 2026

Copy link
Copy Markdown
Author

Hi @russellwheatley 👋 — first, a genuine thank you for pushing the SPM work forward directly on my fork over the past week. The embed-frameworks fix (e4595a52c), the PHAsset guard (a11663051), the auth/crashlytics/storage method files and the Swift bridge helpers are all valuable, and land the release+SPM story much closer to production-ready. I've been actively integrating and testing them on a tvOS 26 target.

I need to raise two concerns publicly on this PR — not just for our project, but because they materially affect any consumer waiting on SPM support to land in a shipping release. Would appreciate direct answers from you (and/or @mikehardy) so the community can plan accordingly.

Concern 1: this PR is no longer scoped to "SPM support"

The PR title says feat(ios): add SPM dependency resolution support alongside CocoaPods. That was the original scope: enable SPM on top of the current stable release line, orthogonal to everything else.

Since ~26-Jun, direct pushes to the head branch have bundled the SPM plumbing with commits that ARE valuable individually but come paired with breaking changes for anyone on the current stable API surface:

SHA Type Impact on stable consumers
71e205d82 refactor(app): remove namespaced root breaks firebase.app() root API
278e23c3e refactor(database): remove deprecated namespaced API breaks database().ref().on('value', cb)
86667089d refactor(analytics): remove deprecated namespaced API breaks analytics() calls
67455ef30 refactor(crashlytics): remove deprecated namespaced API breaks crashlytics() calls
978168dac feat(app)!: migrate app modules to TurboModules requires New Architecture
4097d25ea feat(installations)!: migrate installations to TurboModules requires New Architecture
27ad35cee feat(database)!: migrate database to TurboModules requires New Architecture
15 total remove-namespaced + 3 TurboModules commits see PR history 26-jun to 03-jul

Direct question 1: why are these changes on this PR at all? They're not "SPM support" — they're a v26-shape refactor. Consumers reading a PR titled "SPM support" don't expect breaking API removal + TurboModules mandate inside it.

Concern 2: why not defer TurboModules + namespaced-removal to a v26 release?

SPM adoption should be orthogonal to three separate axes:

  1. Old Architecture vs New Architecture (Fabric) — SPM works fine with either
  2. Namespaced JS API vs modular API — SPM works fine with either
  3. Bridge native modules vs TurboModules — SPM works fine with either

A consumer should be able to enable SPM without touching any of those three. That is what the original PR commits did (05eea1938 feat(ios): add SPM dependency resolution support alongside CocoaPods and the follow-ups on the stable branch).

There's real, immediate demand for SPM in this PR thread:

  • Xcode 26 obligates SPM adoption on iOS/tvOS releases going forward
  • @kellylein noted the VA mobile team is blocked on this
  • @phamleon asked in early July when the release is coming
  • Multiple integrators (including a production tvOS Apple TV app with ~200k users I'm currently shipping) have Xcode 26 as a hard deadline

Direct question 2: why not ship SPM support as a v25.x release now (retro-compatible), and let the TurboModules migration + namespaced-API removal ship in a proper v26.0.0 major later? That's the standard semver approach for changes of this magnitude. It also lets the community plan the v26 migration on its own timeline, rather than being forced into it as a side-effect of wanting SPM.

Right now, an integrator who needs SPM has three options and all three are bad:

  1. Migrate their entire codebase to modular API + TurboModules + NewArch to adopt this PR
  2. Fork the repo internally
  3. Stay on Xcode <26 forever

Reproducible evidence — same target, opposite outcomes

I ran a side-by-side production-shape validation on tvOS 26.4 Simulator (Apple TV 4K 3rd gen), Xcode 26.6, react-native-tvos@0.77.0-0, Old Architecture / Paper renderer, using local tarballs generated with npm pack.

Test A — Stable subset from feature/spm-dependency-support at HEAD bc90cdafe — the original PR base plus your e4595a52c embed-frameworks fix cherry-picked cleanly on top:

Pillar JS side Native SDK Status
App bootstrap ✅ Crashlytics collection enabled at start Validated
Analytics logEvent 12 JS calls 12 native calls 1:1 match
Database ref/on/off 9 JS actions 10 native calls Cascade validated
Database value callback with real data 182 children from live backend Backend confirmed
Crashlytics bootstrap Validated

Result: Build SUCCEEDED, app runs, all pillars pass.

Test Bmain HEAD today (4b42c498b, v25.1.0 with your recent SPM fixes on top of the v26-shape refactors):

Result: Build FAILED at RNFBCrashlyticsModule.mm with:

node_modules/@react-native-firebase/crashlytics/ios/RNFBCrashlytics/RNFBCrashlyticsModule.mm:31:1:
  error: use of '@import' when C++ modules are disabled, consider using -fmodules and -fcxx-modules

node_modules/@react-native-firebase/crashlytics/ios/RNFBCrashlytics/RNFBCrashlyticsModule.mm:79:5:
  error: use of undeclared identifier 'FIRCrashlytics'
(...20+ more undeclared identifier errors on FIRCrashlytics, FIRStackFrame, FIRExceptionModel)

Root cause: @import in .mm (Objective-C++) requires -fcxx-modules, which is not enabled — enabling it breaks React Native JSI headers. This is documented in the code itself with a __has_include(<FirebaseCrashlytics/FirebaseCrashlytics.h>) fallback branch, but with the SPM-only path today the public header path is not exposed to the consumer's HEADER_SEARCH_PATHS, so the preprocessor falls through to the @import branch that doesn't compile in .mm.

Even if we patch the consumer Podfile to expose those headers (feasible, ~4 lines), the JS API surface (FirebaseDataBase().ref(...), firebase.app()) is gone in v25.1.0. So consumers hit a native build error first, then a runtime undefined-is-not-a-function once that's patched — a compounding blocker that's not solvable without upgrading the entire consumer codebase to modular API.

Where I've landed for now

I'm carrying a minimal patched branch internally that has just the SPM plumbing without the v26-shape refactors, plus the e4595a52c embed-frameworks fix pulled in via cherry-pick. That's what's shipping to my production app today. It works, but it's a maintenance burden I'd very much like to hand back upstream once #8933 lands in a v25.x-adoptable shape.

Proposed paths forward

Three options in order of increasing effort:

  1. Retarget feat(ios): add SPM dependency resolution support alongside CocoaPods #8933 to a release/25.x branch instead of main. The stable base still exists at feature/spm-dependency-support HEAD bc90cdafe, which is where the PR originally pointed plus your e4595a52c embed-frameworks fix. Treat that branch as the canonical v25 line. Land further v25 SPM fixes there (podspec / firebase_spm.rb / native .m bits that don't depend on TurboModules). Consumers who want SPM on v25.x install from a v25.x tag; consumers who want v26 install from main after it's tagged as v26.
  2. Split the recent maintainer work into two categories:
    • "SPM plumbing only" (podspec, firebase_spm.rb, Podfile snippets, embed-frameworks post-install) → cherry-pickable onto v25.x, safe to merge into feat(ios): add SPM dependency resolution support alongside CocoaPods #8933.
    • "v26 code shape" (TurboModules, remove-namespaced, .mm conversions, method-file helpers that require Swift-bridge post-refactor) → stays on main, tracks v26 release, not part of this PR.
  3. Publish a v25.x-SPM tag alongside v26 dev. Same effect as (1) but without changing the PR base — just publish a versioned release from the stable branch, and the PR merges into that release train.

I'm happy to do the branch surgery to isolate the v25-safe SPM changes if that helps — you've already done the hard technical work; the split at this point is mostly git mechanics. What I'd like to avoid is publishing v25.2 (or whatever the next semver bump is) with breaking changes hidden inside a "feat(ios): SPM support" PR — that surprises adopters and, honestly, doesn't match the PR title anymore.

Concrete next step I can take right now: if you want, I can open a companion PR (release/25.x-spm) with just the v25-safe subset of your recent work, and we validate on my end (tvOS 26 + RN 0.77 + Paper) before deciding how to route it into a release. The tvOS-old-arch validation I've been running catches exactly the regressions this would prevent (see Test A vs Test B above — same target, same tools, opposite outcomes).

Would that work for you? Happy to hop on a discussion if it's easier than PR comments. And again — thanks for pushing this. Really appreciate the direct collaboration on the fork.

cc @mikehardy — flagging in case you want to weigh in on the release-line strategy.
cc @kellylein @phamleon — you may care about this thread, since it directly affects when a v25.x-adoptable SPM release lands.

— Johan

@mikehardy

mikehardy commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

From a maintainer standpoint, it is not really important that SPM support is orthogonal, it is that as maintainers we have things we need to accomplish, and we process them as we can. In this case it just so happens that SPM support is the last of the 4 major transforms we had stacked up (don't forget converting to typescript!). Typescript, dropping namespace APIs, New Architecture support, and SPM.

New Architecture landed, and v26 will be New Architecture only, it will include the TurboModules breaking changes - there are no supported versions of react-native that still run old architecture. v0.83 of react-native was the last react-native that supported old architecture, and it is older than the "current + 2 releases" support window for react-native. Dropping old architecture support shouldn't be controversial from a support standpoint.

We're not going to devote any time to maintaining non-New Architecture code, including any branch maintenance work to land SPM support on old code here. That's not a good investment of scarce maintainer time.

Dropping namespaced APIs landed - so v26 will be modular APIs only - the namespaced APIs have been deprecated for more than a year, across multiple breaking change releases in fact - which is quite a generous time frame to support them.

Same as New Architecture - there is no reasonable argument to be made in favor of going back on those decisions, and we will not be dedicating any time on supporting old architecture or namespaced APIs, so none of your proposed 3 courses of actions makes sense as a time investment, in my opinion.

Thus your assertion that this PR now "bundles" those changes is not really accurate in my opinion - it is more accurate to say this PR is targeted for a successful merge against current HEAD on main, period. That implies it necessarily needs to work with those two points above - new arch only, modular API only. It's not "bundling" anything. it is "merge-able", something kind of important for a PR...

So, we've landed the rest, it's SPM's turn now. We'll likely release v26 prior to landing SPM support (likely in the next day or so even), but that's just a timing issue. SPM will land and we'll release it as soon as we can. But not based against old versions

Moving forward -

If you have specific technical feedback on the current shape of the PR vs hopes for old branch stuff that could really help though - please post a comment focused just on current technical problems with the PR as it is right now against current main and we can collaborate

@jsnavarroc

Copy link
Copy Markdown
Author

Thanks @mikehardy — appreciate the direct response.

Quick clarification: I never asked for maintenance of the v25.x line. That wasn't the ask, and I understand the maintainer time argument.

What I was actually trying to raise is different: the PR title is feat(ios): add SPM dependency resolution support alongside CocoaPods, but the current head also includes TurboModules migration and namespaced-API removal. Those are separate concerns that don't technically depend on SPM. My hope was that the PR could stay focused on SPM only, so adopting SPM wouldn't require every consumer to also migrate to TurboModules + modular API in the same step.

Not asking for anything to be undone — just noting that when SPM lands, it will effectively force the v26 migration as a side-effect, which wasn't obvious from the PR title.

— Johan

@mikehardy

Copy link
Copy Markdown
Collaborator

This PR, when merged, will be squashed into main. It won't "contain" the already landed breaking changes, it will just land on top of them. The PR only "contains" the other work in so far as main was merged into this branch to prove that it works on main, in 4d5b636

I wouldn't go as far as describing a PR that had main merged into it as "containing" main, per se - it's based on main now but that's different 🤔

…tor builds

The existing iOS matrix only ever runs `xcodebuild build -sdk iphonesimulator`.
Xcode's Archive action forces ONLY_ACTIVE_ARCH=NO and
DEPLOYMENT_POSTPROCESSING=YES (full install-style stripping) for a real
device SDK regardless of project/Podfile settings -- the actual difference
between builds that work from Xcode/simulator and the tvOS TestFlight-only
crash and release+SPM dyld launch failure already reported against this
PR's SPM support.

Add an `ios-release-archive` CI job (spm/cocoapods matrix, no Detox/emulator)
that runs a real, unsigned `xcodebuild archive -destination
'generic/platform=iOS'` and a new verify-ios-release-archive.sh that walks
every embedded binary's otool -L output and fails if any @rpath/*.framework
dependency isn't actually embedded in Frameworks/. This automates, at real
Archive-action fidelity, the check that was previously only done manually
against a Release-iphonesimulator build when firebase_spm.rb's embed phase
was fixed.

Not a substitute for a signed TestFlight/device launch test -- it inspects
the archived bundle statically and would not catch a pure runtime crash on
its own, only the framework-embedding regression class.
Rename ios-spm.md to ios-spm.mdx to match the docs.page convention used by
every other page, add the required frontmatter, and register it in
docs.json — it was previously unreachable from the docs site sidebar. Also
trims the stale Firebase SDK version header and fixes markdown table
formatting/an MDX parsing error that surfaced once the file entered the
`.mdx`-scoped lint:markdown check.
… date

Lead with the CocoaPods trunk shutdown (read-only Dec 2, 2026, per the
CocoaPods blog) as the motivating reason to adopt SPM, instead of the
explicit-modules internals that aren't relevant to most readers.
The RNFBStorage/FIRStorage/StorageTask predicates were added to chase a
specific deadlock that has since been found and fixed upstream. Removing
them lightens the log stream query so CI runners settle faster.
GoogleAdsOnDeviceConversion isn't part of firebase-ios-sdk's own
Package.swift, but Google publishes it as its own standalone SPM package
(googleads/google-ads-on-device-conversion-ios-sdk) independent of the
Firebase package graph. RN's SPMManager keys dependencies by pod target
and package URL, so a second, independent spm_dependency() call resolves
it alongside the existing FirebaseAnalytics dependency -- no need to force
CocoaPods mode to use this feature anymore.
@russellwheatley

Copy link
Copy Markdown
Member

still reading through this - got to the Obj-C helper stuff - that's a pretty big change and I still need to consider it. I wonder if converting to swift internally here in react-native-firebase would simplify things at all - I'm aware of the need for Objective-C in order to complete the journey to native from TurboModules codegen so I'm not sure it would be simplifying at all but I was casting about for any idea to avoid need for one more indirection step of "helper" files to keep our Obj-C "firebase-clean" in the SPM environment

@mikehardy - not sure there is a way around this.

Clang disables @import in Objective-C++ by default, if we allow it with -fcxx-modules flag will break RN's own C++ headers.

Moving to Swift isn't really an option. Right now, we're able to almost verbatim copy/paste Objective-C++ code in to Objective-C, if we converted it all to Swift it would be enormous, more risky and out of scope for this PR in my opinion and wouldn't help minimise diff of PR.

The only thing that I'm not 100% sure, is whether FirebaseStorage/FirebaseRemoteConfig/FirebaseDatabase/FirebaseInAppMessaging, and Auth's core FIRAuth/FIRUser have no product rooted Objective-C headers at all.

@ncooke3 - could you confirm that last bit?

@mikehardy

Copy link
Copy Markdown
Collaborator

still reading through this - got to the Obj-C helper stuff - that's a pretty big change and I still need to consider it. I wonder if converting to swift internally here in react-native-firebase would simplify things at all - I'm aware of the need for Objective-C in order to complete the journey to native from TurboModules codegen so I'm not sure it would be simplifying at all but I was casting about for any idea to avoid need for one more indirection step of "helper" files to keep our Obj-C "firebase-clean" in the SPM environment

@mikehardy - not sure there is a way around this.

That was my analysis as well, I suppose a better way of framing my hesitation is "I haven't found any way around this but it's a big enough change I just wanted one last look", which I did after making the comment -- and my findings were exactly what you found

@ncooke3 - could you confirm that last bit?

This would be my last hope, an appeal to the expert in form of @ncooke3 or @paulb777 - not expecting a miracle but maybe a real ObjC++/Swift expert knows a trick 🤷 . Otherwise, I guess we go for it

…hat to do as a consumer. okf-bundle has also been reduced to remove duplication and any overly verbose descriptions
Restore the pull request to its prior SPM and test-app configuration.
Fixes lint:ios:check indentation violations in method signature
continuation lines across auth, crashlytics, database, firestore,
installations, messaging, perf, remote-config, and storage packages.
@mikehardy

Copy link
Copy Markdown
Collaborator

Error: error: Multiple commands produce '/Users/runner/Library/Developer/Xcode/DerivedData/testing-cqikuezrxdswcudaedbwzwrnlnzj/Build/Intermediates.noindex/ArchiveIntermediates/testing/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FirebaseCoreExtension.framework/FirebaseCoreExtension'
Error: error: Multiple commands produce '/Users/runner/Library/Developer/Xcode/DerivedData/testing-cqikuezrxdswcudaedbwzwrnlnzj/Build/Intermediates.noindex/ArchiveIntermediates/testing/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FirebaseCoreInternal.framework'
Error: error: Multiple commands produce '/Users/runner/Library/Developer/Xcode/DerivedData/testing-cqikuezrxdswcudaedbwzwrnlnzj/Build/Intermediates.noindex/ArchiveIntermediates/testing/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FirebaseSharedSwift.framework'
Error: error: Multiple commands produce '/Users/runner/Library/Developer/Xcode/DerivedData/testing-cqikuezrxdswcudaedbwzwrnlnzj/Build/Intermediates.noindex/ArchiveIntermediates/testing/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FirebaseSharedSwift.framework/FirebaseSharedSwift'
Error: error: Multiple commands produce '/Users/runner/Library/Developer/Xcode/DerivedData/testing-cqikuezrxdswcudaedbwzwrnlnzj/Build/Intermediates.noindex/ArchiveIntermediates/testing/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FirebaseCoreInternal.framework/FirebaseCoreInternal'
Error: error: Multiple commands produce '/Users/runner/Library/Developer/Xcode/DerivedData/testing-cqikuezrxdswcudaedbwzwrnlnzj/Build/Intermediates.noindex/ArchiveIntermediates/testing/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FirebaseCore.framework/FirebaseCore'
Error: error: Multiple commands produce '/Users/runner/Library/Developer/Xcode/DerivedData/testing-cqikuezrxdswcudaedbwzwrnlnzj/Build/Intermediates.noindex/ArchiveIntermediates/testing/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FirebaseCore.framework'
Error: error: Multiple commands produce '/Users/runner/Library/Developer/Xcode/DerivedData/testing-cqikuezrxdswcudaedbwzwrnlnzj/Build/Intermediates.noindex/ArchiveInter

@ncooke3

ncooke3 commented Jul 16, 2026

Copy link
Copy Markdown

The only thing that I'm not 100% sure, is whether FirebaseStorage/FirebaseRemoteConfig/FirebaseDatabase/FirebaseInAppMessaging, and Auth's core FIRAuth/FIRUser have no product rooted Objective-C headers at all.

@ncooke3 - could you confirm that last bit?

@russellwheatley @mikehardy, here is the breakdown:

  • FirebaseStorage: Pure Swift. This is the only library on the list that has no product-rooted Objective-C headers at all. (In SPM, it only compiles the Sources directory with no publicHeadersPath or underlying *Internal target).
  • FirebaseRemoteConfig: Mixed. Contains product-rooted ObjC headers (e.g., FIRRemoteConfig.h). SPM splits it, exposing the headers via a FirebaseRemoteConfigInternal target.
  • FirebaseDatabase: Mixed. Contains product-rooted ObjC headers (e.g., FIRDatabase.h), exposed via FirebaseDatabaseInternal.
  • FirebaseInAppMessaging: Mixed. Contains product-rooted ObjC headers (e.g., FIRInAppMessaging.h), exposed via FirebaseInAppMessagingInternal.
  • FirebaseAuth: Mixed. While the core implementations of Auth and User were rewritten in Swift, the module still maintains product-rooted ObjC headers (FIRAuth.h, FIRUser.h containing forward declarations and typedefs for backward compatibility), exposed via FirebaseAuthInternal.

FirebaseStorage is the only module completely devoid of public Objective-C headers. The other four still maintain a public Objective-C header surface in both their SPM and CocoaPods distributions.

The catch is that these *Internal targets are not really for public use and may be inaccessible.

Right now, we're able to almost verbatim copy/paste Objective-C++ code in to Objective-C

This sounds more straightforward then writing an ObjC shim for each Firebase target.

But I owe answers for #8933 (comment) and #8933 (comment) so I'm looking into those now as they seem related.

…ailures

- Gate the test app's precompiled FirebaseFirestore CocoaPods pod behind
  rnfirebase_spm_disabled? so it no longer collides with the SPM-resolved
  copies of FirebaseCore/FirebaseCoreExtension/FirebaseCoreInternal/
  FirebaseSharedSwift during Xcode Archive builds ("Multiple commands
  produce ... FirebaseCore.framework").
- Link FirebaseCore directly onto the app's own target when SPM is active,
  restoring the "free" linkage CocoaPods always gave apps whose native code
  calls FIRApp/FIROptions APIs directly.
- Fix the SPM embed script to also search Xcode Archive's
  UninstalledProducts folder, not just PackageFrameworks -- real
  `xcodebuild archive` builds were silently embedding zero Firebase SPM
  frameworks and would crash at launch.
…bled

rnfirebase_add_spm_core_to_app_target writes its FirebaseCore package
product dependency into the app's own Xcode project (testing.xcodeproj),
a different project than the one React Native's own SPM integration
manages and cleans up on every install (Pods.xcodeproj). Once that
dependency had been committed into the app's .pbxproj from a prior
SPM-mode `pod install`, switching to `$RNFirebaseDisableSPM = true` and
reinstalling left the stale SPM wiring in place forever: the app target
ended up linked against both Xcode's SPM-resolved firebase-ios-sdk
package graph and the freshly CocoaPods-resolved Firebase/CoreOnly pod
at the same time, and the two copies of Firebase's module graph
collided -- "redefinition of module 'Firebase'" at compile time, and
duplicate App-Intents-metadata build commands at Archive time. This
broke the previously-green `iOS (debug, cocoapods)` and
`iOS Release Archive (cocoapods)` CI jobs.

Add rnfirebase_remove_spm_core_from_app_target as the counterpart to
rnfirebase_add_spm_core_to_app_target: removes the stale product
dependency (and, once nothing else references it, the package
reference itself) whenever SPM is inactive. Also adds Minitest coverage
for both functions -- rnfirebase_add_spm_core_to_app_target previously
had none, which is how this regression went unnoticed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs Attention Workflow: Needs Review Pending feedback or review from a maintainer. Workflow: Waiting for User Response Blocked waiting for user response.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants