Summary
ios/PaywallViewManager.m exports module Paywall but names its class PaywallViewManager. React Native's Fabric legacy-view-manager interop resolves managers by name, so the lookup fails and the process aborts on an assertion during a teardown/reload race.
Paywall is the only manager in the package with this mismatch — both siblings are already consistent, which suggests an oversight rather than intent.
The crash
SIGABRT: Assertion failed: (viewManagerClass),
function constructCoordinator,
file LegacyViewManagerInteropComponentDescriptor.mm, line 125
Mechanism
getViewManagerFromComponentName (LegacyViewManagerInteropComponentDescriptor.mm) derives the class name from the component name by appending "Manager", then tries RCT<name> followed by <name>.
For module Paywall it therefore looks for RCTPaywallManager and PaywallManager. The declared class is PaywallViewManager — the View infix is not present in the module name — so both lookups return nil.
RN then falls back to [bridge moduleForName:@"Paywall"]. That usually succeeds, which is why this isn't seen constantly; but during a teardown/reload race the bridge returns nil, and assert(viewManagerClass) aborts the process.
It's the sole outlier in this package
RCT_EXPORT_MODULE |
Class |
Resolves? |
CustomerCenterView |
CustomerCenterViewManager |
✅ |
RCPaywallFooterView |
RCPaywallFooterViewManager |
✅ |
Paywall |
PaywallViewManager |
❌ |
Conditions
- New Architecture (Fabric) with legacy view-manager interop
- A teardown/reload race — Expo dev-client reloads make this substantially more likely
Probably why it has gone unreported: the assertion names React Native, not RevenueCat, so it reads as an RN bug.
Fix
Either direction works; the first matches your own siblings:
-@interface PaywallViewManager : RCTViewManager
+@interface PaywallManager : RCTViewManager
(and the matching @interface PaywallManager () / @implementation PaywallManager in the .m)
or alternatively:
-RCT_EXPORT_MODULE(Paywall)
+RCT_EXPORT_MODULE(PaywallView)
The rename is the safer of the two — it keeps the JS-facing module name Paywall unchanged.
Version
Verified against 10.5.0 (current at time of writing): ios/PaywallViewManager.h still declares @interface PaywallViewManager : RCTViewManager and ios/PaywallViewManager.m still has RCT_EXPORT_MODULE(Paywall). The file is byte-identical to 10.4.4.
We carry this as a local patch and have had to re-port it on each version bump; we'd much rather drop it. Happy to open a PR if that's useful — just say which of the two fixes you'd prefer.
Environment
react-native-purchases-ui 10.5.0
- React Native 0.86, New Architecture / Fabric enabled
- Expo SDK 57, iOS
Summary
ios/PaywallViewManager.mexports modulePaywallbut names its classPaywallViewManager. React Native's Fabric legacy-view-manager interop resolves managers by name, so the lookup fails and the process aborts on an assertion during a teardown/reload race.Paywallis the only manager in the package with this mismatch — both siblings are already consistent, which suggests an oversight rather than intent.The crash
Mechanism
getViewManagerFromComponentName(LegacyViewManagerInteropComponentDescriptor.mm) derives the class name from the component name by appending"Manager", then triesRCT<name>followed by<name>.For module
Paywallit therefore looks forRCTPaywallManagerandPaywallManager. The declared class isPaywallViewManager— theViewinfix is not present in the module name — so both lookups returnnil.RN then falls back to
[bridge moduleForName:@"Paywall"]. That usually succeeds, which is why this isn't seen constantly; but during a teardown/reload race the bridge returnsnil, andassert(viewManagerClass)aborts the process.It's the sole outlier in this package
RCT_EXPORT_MODULECustomerCenterViewCustomerCenterViewManagerRCPaywallFooterViewRCPaywallFooterViewManagerPaywallPaywallViewManagerConditions
Probably why it has gone unreported: the assertion names React Native, not RevenueCat, so it reads as an RN bug.
Fix
Either direction works; the first matches your own siblings:
(and the matching
@interface PaywallManager ()/@implementation PaywallManagerin the.m)or alternatively:
The rename is the safer of the two — it keeps the JS-facing module name
Paywallunchanged.Version
Verified against 10.5.0 (current at time of writing):
ios/PaywallViewManager.hstill declares@interface PaywallViewManager : RCTViewManagerandios/PaywallViewManager.mstill hasRCT_EXPORT_MODULE(Paywall). The file is byte-identical to 10.4.4.We carry this as a local patch and have had to re-port it on each version bump; we'd much rather drop it. Happy to open a PR if that's useful — just say which of the two fixes you'd prefer.
Environment
react-native-purchases-ui10.5.0