Skip to content

[FR]: Don't let a Play-Services-required product's init failure break other Firebase products sharing the default FirebaseApp #1518

Description

@abogdanov-freeplay

Description

  1. Use case: An app integrates multiple Firebase products together — e.g. Analytics, Crashlytics, and Remote Config (all documented "Recommended" or "Not Required" per Dependencies on Google Play services) alongside Cloud Messaging (documented "Required"). The app needs to keep working, with only the Required product unavailable, on devices without Google Play Services or with broken/outdated GMS — e.g. Huawei AppGallery devices, or (as in firebase/firebase-unity-sdk#1170) Meta Quest 3.

  2. How the SDK currently handles it: Accessing FirebaseApp.DefaultInstance — which every product needs — triggers FirebaseApp.CreateAndTrack(), which eagerly discovers and initializes every Firebase component linked into the build, including ones the app never explicitly calls into. If a Required product fails this eager init because Play Services is unavailable, the resulting Firebase.InitializationException: Firebase modules failed to initialize: (missing dependency) is then thrown by every subsequent native call from any other product that touches CreateAndTrack() — not just the first.

We reproduced this concretely on Android (real Huawei device + a clean emulator with no Google APIs at all): with Cloud Messaging as the Required product, Crashlytics.SetCustomKey(), FirebaseRemoteConfig.get_DefaultInstance(), FirebaseRemoteConfig.get_Keys(), and FirebaseRemoteConfig.SetDefaultsAsync() all throw the identical exception — even though Analytics/Crashlytics/Remote Config are each independently documented as working without Play Services. This isn't triggered by application code: it happens automatically via FirebaseInitProvider's auto-init at process start, confirmed by log timestamps to occur ~3 seconds before our app's first Firebase-related call, and ~1.3 seconds before our app's very first log line at all.

We confirmed with Firebase support (case closed, "expected behavior") that:

firebase_messaging_auto_init_enabled=false does not prevent this — it only gates automatic token generation, not component registration/dependency checking.
Only Remote Config exposes a secondary (non-default) FirebaseApp instance API in the Unity wrapper; Analytics and Crashlytics do not, so there's no workaround via secondary instances either (and even for Remote Config, we found a secondary instance didn't actually avoid the failure in practice).
The only mitigation offered was maintaining a separate build variant with the Required product removed entirely for GMS-less markets — an all-or-nothing tradeoff for what's really a per-device runtime condition.

This exact class of issue was previously reported in firebase/firebase-unity-sdk#170 (2022, with Dynamic Links as the Required product instead of Cloud Messaging), and may be related to the question raised in firebase/firebase-unity-sdk#1170 (2025). We're filing this specifically against the Unity SDK — we haven't verified whether the native Android/iOS SDKs exhibit the same cross-product behavior, since our reproduction and the CreateAndTrack() call stack we observed are from the Unity wrapper.

  1. How we propose the SDK should handle it:
    Each Firebase product should be independently queryable and independently safe to use, instead of sharing one all-or-nothing initialization outcome:

A failure in one component's own dependency resolution (e.g. Cloud Messaging failing on GMS) should not cause FirebaseApp.CreateAndTrack() (or its equivalent) to throw when a completely unrelated component (e.g. Crashlytics, Remote Config) is touched. The native layer's eager validation should be scoped per-component, not global — a broken branch shouldn't take down the rest.
On top of that, expose a per-product "is it safe to use this component" check, so an app can decide per-service whether to call into it — the same pattern we already use ourselves for the whole-device GMS check (CheckAndFixDependenciesAsync()), just at the right granularity. Today that check only tells you the aggregate device-wide GMS status, not which specific product is actually broken. Critically, this check shouldn't be a required safety net: even if an app skips it, or calls into a product that turns out to be unavailable, that call should fail gracefully and locally, without affecting unrelated components.

API Proposal

bool FirebaseApp.IsComponentAvailable(Type componentType);

Firebase Product(s)

Analytics, Crashlytics, Remote Config, Messaging, All

Targeted Platform(s)

Android

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions