Summary
On iOS, the React Native SDK's underlying FronteggSwift singleton (FronteggApp.init()) eagerly reads Frontegg.plist from the main bundle and calls fatalError if it's missing. Because the singleton fires the moment @frontegg/react-native is imported (not when it's first used), any consumer that wants to ship the SDK behind a feature gate / per-variant rollout has no way to keep it dormant in builds that don't include the plist.
This makes a phased iOS rollout effectively impossible without significant Xcode / Pod gymnastics on the consumer side.
Repro
- RN app integrates
@frontegg/react-native.
Frontegg.plist is bundled only in one target (e.g. a staging variant), not in production / white-label variants.
- JS code attempts to gate the SDK at import time:
// src/App.tsx
import { FronteggWrapper } from '@frontegg/react-native'; // ← fires here
return variant === 'staging' ? <FronteggWrapper>{children}</FronteggWrapper> : children;
- Any non-staging variant crashes on launch with:
Thread 1: Fatal error: Could not load Frontegg Plist:
Missing Frontegg.plist file with 'clientId' and 'baseUrl' entries in main bundle!
…before any React Native code runs. The JS gate doesn't help — the import alone triggers the singleton.
Root cause (as best we can tell from FronteggSwift)
FronteggApp.init() is called at module-load time (Swift static singleton init pattern).
- It calls
Bundle.main.url(forResource: \"Frontegg\", withExtension: \"plist\") and then fatalErrors if nil (PlistHelper.swift → FronteggApp.swift).
- The RN bridge imports trigger this on the very first JS-side
import of any symbol from @frontegg/react-native.
Contrast with Android
The Android SDK reads its config via safeGetValueFromBuildConfig(..., default) — missing fields fall back to defaults rather than crashing the process. We verified empirically: an Android variant without the Frontegg buildConfigFields still launches and runs to the home screen (it just can't authenticate, as expected). The iOS side should behave the same way.
Proposed directions (not prescriptive)
We're happy to follow Frontegg's preferred shape — flagging the architectural issue more than the specific fix. Some options:
- Lazy init — defer the
Bundle.main plist read until first SDK call (FronteggApp.shared.login(...) etc.). Imports become side-effect-free.
- Non-fatal missing-plist — log + no-op when plist is absent, return an SDK instance that errors only on calls. Matches Android's existing behaviour.
- Programmatic init API —
FronteggApp.init(clientId:baseUrl:) that consumers call explicitly. Plist becomes optional sugar on top.
(1) or (2) would be minimally invasive. (3) is a larger API change but the most explicit.
Workarounds we tried (and why they're not great)
| Approach |
Outcome |
JS-level lazy import() only inside the gate |
Doesn't help — once the import resolves, the singleton fires. |
| Frontegg.plist in every iOS target |
Surfaces credentials in production builds; security/compliance concern. |
| Conditional Pod linking (FronteggRN only in staging target) |
Workable but invasive on the consumer side; defeats the point of a JS gate. |
| Metro resolver / noop shim |
Works for static imports but only the JS import — native pod link still runs init. |
Environment
@frontegg/react-native@1.2.16
- React Native 0.80
- iOS 18.x, Xcode 16
- Reproduced on iPhone 17 device and iOS Simulator
Related
We've also opened a small batch of Android-side PRs against this repo (JVM target, currentActivity deprecation, BuildConfig lookup for white-label apps). This iOS item is the one architectural change we wanted to raise as an issue rather than a unilateral PR, since the right API direction is Frontegg's call.
Happy to test prototype builds or contribute a PR once a direction is chosen.
Summary
On iOS, the React Native SDK's underlying
FronteggSwiftsingleton (FronteggApp.init()) eagerly readsFrontegg.plistfrom the main bundle and callsfatalErrorif it's missing. Because the singleton fires the moment@frontegg/react-nativeis imported (not when it's first used), any consumer that wants to ship the SDK behind a feature gate / per-variant rollout has no way to keep it dormant in builds that don't include the plist.This makes a phased iOS rollout effectively impossible without significant Xcode / Pod gymnastics on the consumer side.
Repro
@frontegg/react-native.Frontegg.plistis bundled only in one target (e.g. a staging variant), not in production / white-label variants.…before any React Native code runs. The JS gate doesn't help — the import alone triggers the singleton.
Root cause (as best we can tell from FronteggSwift)
FronteggApp.init()is called at module-load time (Swift static singleton init pattern).Bundle.main.url(forResource: \"Frontegg\", withExtension: \"plist\")and thenfatalErrors if nil (PlistHelper.swift→FronteggApp.swift).importof any symbol from@frontegg/react-native.Contrast with Android
The Android SDK reads its config via
safeGetValueFromBuildConfig(..., default)— missing fields fall back to defaults rather than crashing the process. We verified empirically: an Android variant without the FronteggbuildConfigFieldsstill launches and runs to the home screen (it just can't authenticate, as expected). The iOS side should behave the same way.Proposed directions (not prescriptive)
We're happy to follow Frontegg's preferred shape — flagging the architectural issue more than the specific fix. Some options:
Bundle.mainplist read until first SDK call (FronteggApp.shared.login(...)etc.). Imports become side-effect-free.FronteggApp.init(clientId:baseUrl:)that consumers call explicitly. Plist becomes optional sugar on top.(1) or (2) would be minimally invasive. (3) is a larger API change but the most explicit.
Workarounds we tried (and why they're not great)
import()only inside the gateEnvironment
@frontegg/react-native@1.2.16Related
We've also opened a small batch of Android-side PRs against this repo (JVM target,
currentActivitydeprecation,BuildConfiglookup for white-label apps). This iOS item is the one architectural change we wanted to raise as an issue rather than a unilateral PR, since the right API direction is Frontegg's call.Happy to test prototype builds or contribute a PR once a direction is chosen.