Paywall component freezes and crashes the app on iOS when rendered in certain conditions
- [x] I have updated Purchases SDK to the latest version
- [x] I have read the Contribution Guidelines
- [x] I have searched the Community
- [x] I have read docs.revenuecat.com
- [x] I have searched for existing Github issues
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
- Platform: iOS
- SDK version: 9.2.0
- OS version: 18.6
- Xcode/Android Studio version: XCode 16.4
- React Native version: 0.79.5
- SDK installation (CocoaPods + version or manual):
- 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
- 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.
👀 We've just linked this issue to our internal tracker and notified the team. Thank you for reporting, we're checking this out!
@leonardorib Thanks for reporting this and with all the details! We will be looking into right away 💪
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:
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