react-native-purchases icon indicating copy to clipboard operation
react-native-purchases copied to clipboard

Paywall component freezes and crashes the app on iOS when rendered in certain conditions

Open leonardorib opened this issue 4 months ago • 4 comments

Describe the bug When showing the paywall with the PurchasesUI.Paywall component on iOS after navigating to a react-navigation screen, the app can freeze if you need to delay the mounting of the paywall component. There are no errors thrown or warns.

From my tests it happens only in the first time you show the paywall, if you successfully show it once, then you can't repro in the same app open. It also seems to be easier to reproduce depending on your react-navigation structure, which can indicate a potential conflict between the revcat paywall and react-navigation.


1. Environment

  1. Platform: iOS
  2. SDK version: 9.2.0
  3. OS version: 18.6
  4. Xcode/Android Studio version: XCode 16.4
  5. React Native version: 0.79.5
  6. SDK installation (CocoaPods + version or manual):
  7. How widespread is the issue. Percentage of devices affected. 100% of tested iOS real devices

We verified this on real iOS devices but not in the simulator. Does not happen on Android devices.

Other relevant package versions:

"react": "19.0.0",
"react-native": "0.79.5",
"react-native-purchases": "^9.2.0",
"react-native-purchases-ui": "^9.2.0",
"react-native-reanimated": "^3.19.1",
"react-native-safe-area-context": "^5.6.0",
"react-native-screens": "^4.13.1",
"react-native-gesture-handler": "^2.28.0",
"@react-navigation/bottom-tabs": "^7.4.6",
"@react-navigation/native": "^7.1.17",
"@react-navigation/stack": "ˆ7.4.7",

2. Debug logs that reproduce the issue

There are no errors thrown or warns. The app will eventually crash if you background/foreground once it freezes but it's simply because it's unresponsive.


3. Steps to reproduce, with a description of expected vs. actual behavior

I created a gist with a minimal app where I am reproducing the problem:

https://gist.github.com/leonardorib/b21a00b1d9e8b760f5c125e73cd68f5d

To repro, try to navigate to the paywall quickly. Just open the app and press the buttons to get there as shown in the video.

The issue is not guaranteed to happen. But in at most 3 tries I can get one.

If you don't get the issue, completely quit the app and reopen to try a new one.

This is how the freeze/crash looks like:

https://gist.github.com/user-attachments/assets/acc0b997-9f95-4826-b187-1184d014cd35

This is the expected behavior:

https://gist.github.com/user-attachments/assets/9588047e-af39-45ed-8557-056fa1283035


  1. Other information (e.g. stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, etc.)

Key aspects:

  • The navigation structure might contribute (navigators hierachy). When I tried to reproduce in a simpler navigation structure with a single stack navigator with some screens, it was harder to make it freeze, which is why I recreated something closer to our real app.
  • Although react-navigation might be involved. If i replace <PurchasesUI.Paywall /> with something like <View><Text>Hello world</Text></View>, the issue doesn't happen. It only happened when the component being mounted was the paywall, which is the reason I am reporting it here.
  • It seems to happen when you delay the mounting of the paywall after navigating to the screen (e.g when loading something before showing the paywall). It feels like it is when the mounting happens right in the middle of the navigation animation

There is a workaround that makes it consistently work for me, which is replacing:

useEffect(() => {
  // Simulates a loading state before showing the paywall
  setTimeout(() => {
    setCanShow(true);
  }, CAN_SHOW_DELAY_MS);
}, []);

with:

import { InteractionManager } from 'react-native';
//...
useEffect(() => {
  // Simulates a loading state before showing the paywall
  setTimeout(() => {
    InteractionManager.runAfterInteractions(() => {
      setCanShow(true);
    })
  }, CAN_SHOW_DELAY_MS);
}, []);

This ensures animations and interactions are executed first. More info: https://reactnative.dev/docs/interactionmanager

To this moment, I didn't get the issue when ensuring I wait for runAfterInteractions, but since I don't know exactly what is behind the problem, I can't guarantee the safety of it.


Additional context

It could be that this ends up being an issue on react-navigation or even react-native-screens, but since I can only repro when trying to render the Paywall component specifically, I am reporting it here.

Let me know if you guys can reproduce it on your end with my gist.

leonardorib avatar Aug 13 '25 22:08 leonardorib

👀 We've just linked this issue to our internal tracker and notified the team. Thank you for reporting, we're checking this out!

RCGitBot avatar Aug 13 '25 22:08 RCGitBot

@leonardorib Thanks for reporting this and with all the details! We will be looking into right away 💪

joshdholtz avatar Aug 13 '25 22:08 joshdholtz

Hi @joshdholtz, I just wanted to follow up on this. Is there any progress or ETA that you could share? Thank you so much! :pray:

leonardorib avatar Sep 25 '25 21:09 leonardorib

having the same issue, super irritating. it's happened in past versions too, but a viable work around was wrapping the RC components in a ScrollView - this no longer works.

currently, our only work around is RevenueCatUI.presentPaywall

wrightman-henry avatar Nov 03 '25 20:11 wrightman-henry