Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions .github/workflows/tests_e2e_ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,21 @@ jobs:
// we want to test debug and release - they generate different code
let buildmode = ['debug', 'release'];

// Test both SPM and CocoaPods dependency resolution modes
let depResolution = ['spm', 'cocoapods'];

return {
"iteration": iterationArray,
"buildmode": buildmode
"buildmode": buildmode,
"dep-resolution": depResolution
}
- name: Debug Output
run: echo "${{ steps.build-matrix.outputs.result }}"

# This uses the matrix generated from the matrix-prep stage
# it will run unit tests on whatever OS combinations are desired
ios:
name: iOS (${{ matrix.buildmode }}, ${{ matrix.iteration }})
name: iOS (${{ matrix.buildmode }}, ${{ matrix.dep-resolution }}, ${{ matrix.iteration }})
runs-on: macos-15
needs: matrix_prep
# TODO matrix across APIs, at least 11 and 15 (lowest to highest)
Expand Down Expand Up @@ -182,7 +186,7 @@ jobs:
- uses: hendrikmuhs/ccache-action@v1
name: Xcode Compile Cache
with:
key: ${{ runner.os }}-${{ matrix.buildmode }}-ios-v3 # makes a unique key w/related restore key internally
key: ${{ runner.os }}-${{ matrix.buildmode }}-${{ matrix.dep-resolution }}-ios-v3 # makes a unique key w/related restore key internally
save: "${{ github.ref == 'refs/heads/main' }}"
create-symlink: true
max-size: 1500M
Expand Down Expand Up @@ -214,8 +218,21 @@ jobs:
continue-on-error: true
with:
path: tests/ios/Pods
key: ${{ runner.os }}-ios-pods-v3-${{ hashFiles('tests/ios/Podfile.lock') }}
restore-keys: ${{ runner.os }}-ios-pods-v3
key: ${{ runner.os }}-${{ matrix.dep-resolution }}-ios-pods-v3-${{ hashFiles('tests/ios/Podfile.lock') }}
restore-keys: ${{ runner.os }}-${{ matrix.dep-resolution }}-ios-pods-v3

- name: Configure Dependency Resolution Mode
run: |
if [[ "${{ matrix.dep-resolution }}" == "cocoapods" ]]; then
echo "Configuring CocoaPods-only mode (disabling SPM)"
cd tests/ios
sed -i '' "s/^linkage = 'dynamic'/linkage = 'static'/" Podfile
printf '%s\n' '$RNFirebaseDisableSPM = true' | cat - Podfile > Podfile.tmp && mv Podfile.tmp Podfile
sed -i '' "/SWIFT_ENABLE_EXPLICIT_MODULES/d" Podfile
echo "Podfile configured for CocoaPods-only mode"
else
echo "Using default SPM mode (dynamic linkage)"
fi

- name: Pod Install
uses: nick-fields/retry@v3
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/tests_jest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ jobs:
retry_wait_seconds: 60
max_attempts: 3
command: yarn
- name: Test Firebase SPM Helper
run: ruby packages/app/__tests__/firebase_spm_test.rb
- name: Jest
run: yarn tests:jest-coverage
- uses: codecov/codecov-action@v5
Expand Down
760 changes: 760 additions & 0 deletions docs/ios-spm.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docs/sidebar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
- '/migrating-to-v24'
- - TypeScript
- '/typescript'
- - iOS SPM Support
- '/ios-spm'
- - Platforms
- '/platforms'
- - Release Notes
Expand Down
60 changes: 45 additions & 15 deletions packages/analytics/RNFBAnalytics.podspec
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'json'
require '../app/firebase_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.

maintainer note (mirrored in similar note in firebase_spm.rb itself) to verify this is okay in monorepo (possibly hoisted)/pnpm/etc cases - there is likely a known-good inter-package local file resolution mechanism and it is likely not a simple ../<packagename>/ path unfortunately

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.

Same monorepo/pnpm note applies here. The ../app/ path works with the standard node_modules/@react-native-firebase/ layout. Added documentation in firebase_spm.rb and the README about this assumption.

package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
appPackage = JSON.parse(File.read(File.join('..', 'app', 'package.json')))

Expand Down Expand Up @@ -45,27 +46,56 @@ Pod::Spec.new do |s|
end

# Firebase dependencies
s.dependency 'FirebaseAnalytics/Core', firebase_sdk_version
if defined?($RNFirebaseAnalyticsWithoutAdIdSupport) && ($RNFirebaseAnalyticsWithoutAdIdSupport == true)
Pod::UI.puts "#{s.name}: Not installing FirebaseAnalytics/IdentitySupport Pod, no IDFA will be collected."
# Analytics has conditional dependencies that vary between SPM and CocoaPods.
# SPM: use FirebaseAnalyticsCore when $RNFirebaseAnalyticsWithoutAdIdSupport = true
# to avoid GoogleAppMeasurement APM symbols (APMETaskManager, APMMeasurement)
# that require FirebasePerformance at link time.
# CocoaPods: IdentitySupport is a separate subspec controlled by $RNFirebaseAnalyticsWithoutAdIdSupport.
if defined?(spm_dependency) && !defined?($RNFirebaseDisableSPM) &&
defined?($RNFirebaseAnalyticsWithoutAdIdSupport) && $RNFirebaseAnalyticsWithoutAdIdSupport
# FirebaseAnalyticsCore uses GoogleAppMeasurementCore (no IDFA, no APM objects).
# FirebaseAnalytics uses GoogleAppMeasurement which has APMETaskManager/APMMeasurement
# cross-references that cause linker errors when FirebasePerformance is not linked.
Pod::UI.puts "#{s.name}: Using FirebaseAnalyticsCore SPM product (no IDFA, uses GoogleAppMeasurementCore)."
firebase_dependency(s, firebase_sdk_version, ['FirebaseAnalyticsCore'], 'FirebaseAnalytics/Core')
else
if !defined?($RNFirebaseAnalyticsWithoutAdIdSupport)
Pod::UI.puts "#{s.name}: Using FirebaseAnalytics/IdentitySupport with Ad Ids. May require App Tracking Transparency. Not allowed for Kids apps."
Pod::UI.puts "#{s.name}: You may set variable `$RNFirebaseAnalyticsWithoutAdIdSupport=true` in Podfile to use analytics without ad ids."
end
s.dependency 'FirebaseAnalytics/IdentitySupport', firebase_sdk_version
firebase_dependency(s, firebase_sdk_version, ['FirebaseAnalytics'], 'FirebaseAnalytics/Core')
end

# Special pod for on-device conversion
if defined?($RNFirebaseAnalyticsEnableAdSupport) && ($RNFirebaseAnalyticsEnableAdSupport == true)
Pod::UI.puts "#{s.name}: Adding Apple AdSupport.framework dependency for optional analytics features"
s.frameworks = 'AdSupport'
unless defined?(spm_dependency)
# CocoaPods-only: conditional IdentitySupport subspec
if defined?($RNFirebaseAnalyticsWithoutAdIdSupport) && ($RNFirebaseAnalyticsWithoutAdIdSupport == true)
Pod::UI.puts "#{s.name}: Not installing FirebaseAnalytics/IdentitySupport Pod, no IDFA will be collected."
else
if !defined?($RNFirebaseAnalyticsWithoutAdIdSupport)
Pod::UI.puts "#{s.name}: Using FirebaseAnalytics/IdentitySupport with Ad Ids. May require App Tracking Transparency. Not allowed for Kids apps."
Pod::UI.puts "#{s.name}: You may set variable `$RNFirebaseAnalyticsWithoutAdIdSupport=true` in Podfile to use analytics without ad ids."
end
s.dependency 'FirebaseAnalytics/IdentitySupport', firebase_sdk_version
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

IdentitySupport skipped when SPM disabled on RN >= 0.75

High Severity

The unless defined?(spm_dependency) guard on line 65 only checks whether spm_dependency exists, but doesn't account for the $RNFirebaseDisableSPM opt-out flag. When a user has RN >= 0.75 (so spm_dependency is defined) AND sets $RNFirebaseDisableSPM = true to force CocoaPods, this entire block is skipped — silently omitting the FirebaseAnalytics/IdentitySupport CocoaPods dependency. The condition needs to also check !defined?($RNFirebaseDisableSPM) to match the pattern used elsewhere.

Fix in Cursor Fix in Web

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

end
end

# Special pod for on-device conversion
# AdSupport framework (works with both SPM and CocoaPods)
if defined?($RNFirebaseAnalyticsEnableAdSupport) && ($RNFirebaseAnalyticsEnableAdSupport == true)
Pod::UI.puts "#{s.name}: Adding Apple AdSupport.framework dependency for optional analytics features"
s.frameworks = 'AdSupport'
end

# GoogleAdsOnDeviceConversion (CocoaPods only)
# This is a static xcframework distributed separately from firebase-ios-sdk.
# It is NOT available as an SPM product in the firebase-ios-sdk Package.swift.
# When using SPM (dynamic linkage), this static xcframework causes duplicate
# symbol errors. Use CocoaPods mode ($RNFirebaseDisableSPM = true) if you need
# on-device conversion measurement.
# See: https://developers.google.com/google-ads/api/docs/conversions/upload-identifiers
if defined?($RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion) && ($RNFirebaseAnalyticsGoogleAppMeasurementOnDeviceConversion == true)
Pod::UI.puts "#{s.name}: GoogleAdsOnDeviceConversion pod added"
s.dependency 'GoogleAdsOnDeviceConversion'
if defined?(spm_dependency) && !defined?($RNFirebaseDisableSPM)
Pod::UI.warn "#{s.name}: GoogleAdsOnDeviceConversion is not available in SPM mode. " \
"Set $RNFirebaseDisableSPM = true in your Podfile to use this feature."
else
Pod::UI.puts "#{s.name}: GoogleAdsOnDeviceConversion pod added"
s.dependency 'GoogleAdsOnDeviceConversion'
end
end

if defined?($RNFirebaseAsStaticFramework)
Expand Down
5 changes: 5 additions & 0 deletions packages/analytics/ios/RNFBAnalytics/RNFBAnalyticsModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
*
*/

#if __has_include(<Firebase/Firebase.h>)
#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)

Copy link
Copy Markdown
Author

@jsnavarroc jsnavarroc Apr 22, 2026

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.

#endif
#import <React/RCTUtils.h>

#if __has_include(<RNFBAnalytics/RNFBAnalytics-Swift.h>)
Expand Down
3 changes: 2 additions & 1 deletion packages/app-check/RNFBAppCheck.podspec
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'json'
require '../app/firebase_spm'
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
appPackage = JSON.parse(File.read(File.join('..', 'app', 'package.json')))

Expand Down Expand Up @@ -44,7 +45,7 @@ Pod::Spec.new do |s|
end

# Firebase dependencies
s.dependency 'Firebase/AppCheck', firebase_sdk_version
firebase_dependency(s, firebase_sdk_version, ['FirebaseAppCheck'], 'Firebase/AppCheck')

if defined?($RNFirebaseAsStaticFramework)
Pod::UI.puts "#{s.name}: Using overridden static_framework value of '#{$RNFirebaseAsStaticFramework}'"
Expand Down
9 changes: 8 additions & 1 deletion packages/app-check/ios/RNFBAppCheck/RNFBAppCheckModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@
*
*/

#if __has_include(<Firebase/Firebase.h>)
#import <Firebase/Firebase.h>
#import <FirebaseAppCheck/FIRAppCheck.h>
#elif __has_include(<FirebaseAppCheck/FirebaseAppCheck.h>)
#import <FirebaseAppCheck/FirebaseAppCheck.h>
Comment on lines +18 to +21
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

Copy link
Copy Markdown
Author

@jsnavarroc jsnavarroc Apr 22, 2026

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.

#import <FirebaseCore/FirebaseCore.h>
#else
@import FirebaseCore;
@import FirebaseAppCheck;
#endif

#import <React/RCTUtils.h>

Expand Down
9 changes: 8 additions & 1 deletion packages/app-check/ios/RNFBAppCheck/RNFBAppCheckProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@
*
*/

#if __has_include(<Firebase/Firebase.h>)
#import <Firebase/Firebase.h>
#import <FirebaseAppCheck/FIRAppCheck.h>
#elif __has_include(<FirebaseAppCheck/FirebaseAppCheck.h>)
#import <FirebaseAppCheck/FirebaseAppCheck.h>
#import <FirebaseCore/FirebaseCore.h>
Comment on lines +18 to +22
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.

Same questions on imports here - I note that Firebase vs FirebaseCore varies here though - I may have missed that above and that might explain the entire structure

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 catch on Firebase vs FirebaseCore. The difference is intentional: AppCheck needs both FirebaseCore (for FIRApp) and FirebaseAppCheck (for FIRAppCheck, FIRAppCheckProvider). The umbrella <Firebase/Firebase.h> includes both transitively, but when importing individually (middle branch), we need both explicitly since FirebaseAppCheck doesn't re-export FirebaseCore.

#else
@import FirebaseCore;
@import FirebaseAppCheck;
#endif

@interface RNFBAppCheckProvider : NSObject <FIRAppCheckProvider>

Expand Down
3 changes: 2 additions & 1 deletion packages/app-distribution/RNFBAppDistribution.podspec
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'json'
require '../app/firebase_spm'
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
appPackage = JSON.parse(File.read(File.join('..', 'app', 'package.json')))

Expand Down Expand Up @@ -42,7 +43,7 @@ Pod::Spec.new do |s|
end

# Firebase dependencies
s.dependency 'Firebase/AppDistribution', firebase_sdk_version
firebase_dependency(s, firebase_sdk_version, ['FirebaseAppDistribution-Beta'], 'Firebase/AppDistribution')

if defined?($RNFirebaseAsStaticFramework)
Pod::UI.puts "#{s.name}: Using overridden static_framework value of '#{$RNFirebaseAsStaticFramework}'"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
*
*/

#if __has_include(<Firebase/Firebase.h>)
#import <Firebase/Firebase.h>
#else
@import FirebaseCore;
@import FirebaseAppDistribution;
#endif
#import <React/RCTUtils.h>

#import "RNFBApp/RNFBSharedUtils.h"
Expand Down
6 changes: 6 additions & 0 deletions packages/app/.npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,9 @@ android/.settings
type-test.ts
scripts
__tests__

# Force include generated version file (needed for linking).
# This file is in .gitignore but must be in the published npm package.
# Note: this package does not use a "files" array in package.json,
# so .npmignore is the sole mechanism controlling published file set.
!ios/RNFBApp/RNFBVersion.m
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.

should this be added to the files array in app/package.json as well? .npmignore historically does work but can have subtle interaction with package.json::files element and I've had problems here before when the implied inclusion from .npmignore didn't result in the actual packaged file set that was desired

Copy link
Copy Markdown
Author

@jsnavarroc jsnavarroc Apr 22, 2026

Choose a reason for hiding this comment

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

Good point. This package doesn't use a files array in package.json, so .npmignore is the sole mechanism. I've added a clarifying comment in .npmignore explaining this. Adding a files array would change the inclusion logic for the entire package (allowlist vs denylist), so I opted to document the current approach clearly instead. Happy to add files if you prefer that direction.

114 changes: 114 additions & 0 deletions packages/app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,120 @@ yarn add @react-native-firebase/app

- [Utils](https://rnfirebase.io/app/utils)

## iOS Dependency Resolution: SPM vs CocoaPods

Starting with React Native 0.75+, `@react-native-firebase` supports **Swift Package Manager (SPM)** for resolving Firebase iOS SDK dependencies. SPM is enabled by default when the `spm_dependency` macro is available (injected by React Native >= 0.75) — no configuration needed.

### How it works

Each RNFB module uses `firebase_dependency()` (defined in `firebase_spm.rb`) to declare its Firebase dependencies. This helper automatically chooses between:

| Condition | Resolution | When to use |
|-----------|-----------|-------------|
| RN >= 0.75 and `$RNFirebaseDisableSPM` **not set** | **SPM** (default) | Dynamic linkage / pre-built RN core (`use_frameworks! :linkage => :dynamic`) |
| `$RNFirebaseDisableSPM = true` in Podfile | **CocoaPods** | Static linkage / no pre-built RN core (`use_frameworks! :linkage => :static`) |
| RN < 0.75 | **CocoaPods** (automatic fallback) | Older React Native versions without `spm_dependency` support |

> **Note on linkage:** firebase-ios-sdk SPM products use dynamic linkage. When using `use_frameworks! :linkage => :static`, each pod embeds its own copy of Firebase SPM products, causing duplicate symbol errors. Use CocoaPods mode (`$RNFirebaseDisableSPM = true`) with static linkage.

### Configuration

#### Option A — SPM (default, recommended for Xcode 26+)

No changes needed. Just make sure your Podfile uses dynamic linkage:

```ruby
# Podfile
use_frameworks! :linkage => :dynamic
```
Comment on lines +59 to +64
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.

What's the instruction for Expo people in this case? That's our majority use case now I believe - and if it is not yet it definitely will be in the future

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.

Added an Expo section in the latest commit with expo-build-properties examples for both SPM (dynamic) and CocoaPods (static) modes. Also noted that disabling SPM in Expo requires a config plugin to prepend $RNFirebaseDisableSPM = true to the generated Podfile.


> **Xcode 26 note:** If you see build errors about `FirebaseCoreInternal` or `FirebaseSharedSwift`
> module resolution, add this to your Podfile `post_install`:
> ```ruby
> config.build_settings['SWIFT_ENABLE_EXPLICIT_MODULES'] = 'NO'
> ```
> This does NOT disable SPM — it only tells the Swift compiler to use implicit module discovery
> (the Xcode 16 default) so transitive SPM targets are resolved automatically.
Comment on lines +66 to +72
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.

We'll need an Expo section here. It will likely involve instruction to add module expo-build-properties and put something in app.json or similar

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.

Done, Expo section added in latest commit. Includes expo-build-properties config for dynamic linkage and a note about needing a config plugin to add $RNFirebaseDisableSPM = true for static linkage.


#### Option B — CocoaPods only

Add this line at the top of your Podfile (before any `target` block):

```ruby
# Podfile
$RNFirebaseDisableSPM = true
```

This forces all RNFB modules to use traditional `s.dependency` CocoaPods declarations.
You can use either static or dynamic linkage with this option.
Comment on lines +76 to +84
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.

Similarly - if there is something Expo people need to do to add a Podfile directive we'll need to explain it here or we'll have a lot of issues opened in the repo later about it

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.

Covered in the Expo section added in latest commit.


#### Expo

For Expo managed projects, use `expo-build-properties` to configure linkage and Podfile directives:

```json
// app.json
{
"expo": {
"plugins": [
[
"expo-build-properties",
{
"ios": {
"useFrameworks": "dynamic"
}
}
]
]
}
}
```

To disable SPM in Expo, add a Podfile directive via a config plugin or `app.json`:

```json
// app.json
{
"expo": {
"plugins": [
[
"expo-build-properties",
{
"ios": {
"useFrameworks": "static",
"extraPods": []
}
}
]
]
}
}
```

Then create a small [config plugin](https://docs.expo.dev/config-plugins/introduction/) to prepend
`$RNFirebaseDisableSPM = true` to the generated Podfile, or add it manually if you have ejected.

### How to verify

During `pod install`, you will see messages indicating which resolution mode is active:

```
# SPM mode:
[react-native-firebase] RNFBApp: Using SPM for Firebase dependency resolution (products: FirebaseCore)
[react-native-firebase] RNFBAuth: Using SPM for Firebase dependency resolution (products: FirebaseAuth)

# CocoaPods mode:
[react-native-firebase] RNFBApp: SPM disabled ($RNFirebaseDisableSPM = true), using CocoaPods for Firebase dependencies
```

### Monorepo / pnpm notes

The `firebase_spm.rb` helper is loaded by each RNFB podspec via `require '../app/firebase_spm'`.
This relative path assumes the standard `node_modules/@react-native-firebase/` layout. If your
package manager hoists dependencies differently (e.g., pnpm strict mode), you may need to verify
that the require path resolves correctly. The SPM URL is read from
`@react-native-firebase/app/package.json` at the location of `firebase_spm.rb`.

## License

- See [LICENSE](/LICENSE)
Expand Down
3 changes: 2 additions & 1 deletion packages/app/RNFBApp.podspec
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'json'
require './firebase_json'
require './firebase_spm'
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
firebase_sdk_version = package['sdkVersions']['ios']['firebase']
firebase_ios_target = package['sdkVersions']['ios']['iosTarget']
Expand Down Expand Up @@ -61,7 +62,7 @@ Pod::Spec.new do |s|
end

# Firebase dependencies
s.dependency 'Firebase/CoreOnly', firebase_sdk_version
firebase_dependency(s, firebase_sdk_version, ['FirebaseCore', 'FirebaseInstallations'], 'Firebase/CoreOnly')

if defined?($RNFirebaseAsStaticFramework)
Pod::UI.puts "#{s.name}: Using overridden static_framework value of '#{$RNFirebaseAsStaticFramework}'"
Expand Down
Loading
Loading