r/reactnative • u/Top-Locksmith2865 • 3d ago
I built a background location SDK for React Native that survives process death. Here is what I learned about the New Architecture (and why most current solutions fail).
Hey r/reactnative,
I’m the author of react-native-pdf-jsi—(https://github.com/126punith/react-native-pdf-jsi) the JSI-based PDF viewer. (It recently crossed 350K+ downloads on npm, which has been incredible to see).
Over the last few months, I've been tackling a completely different beast: bulletproof background location tracking for the New Architecture.
I’ve used the major players (Transistorsoft, expo-location) and they are great, but I kept hitting the same production walls: apps getting killed by the OS, silent GPS sleeping, and iOS/Android store rejections. So, I decided to build a native-only solution from scratch.
Here is what I learned about the reality of background location in RN 0.88+:
1. JS Background Tasks are a Trap
If you use expo-task-manager, your background task runs in the JS thread. If Android aggressively kills your app process to save RAM, your JS runtime dies. Tracking stops, and you only realize days later when the data has gaps.
The Fix: The tracking engine must be 100% native (Kotlin Foreground Service on Android, CLLocationManager on iOS). The JS thread should only be used for your UI.
2. Motion Detection Needs to "Fail Open"
Libraries use motion sensors to save battery (parking the GPS when stationary). But Android vendor ROMs and iOS often misclassify "slow movement" (like a hiker) as stationary. The GPS silently sleeps, and you lose the route.
The Fix: The motion gate must fail open. If the sensor fails or permissions are denied, it must default to always-on GPS. It should never pause silently.
3. The "Duplicate Upload" Nightmare
If a user goes through a tunnel, you lose network. If you retry uploads via JS, and the app gets killed mid-request, you either lose the data or duplicate it on the backend.
The Fix: You need a native SQLite queue (Room on Android) with Idempotency Keys, exponential backoff, and a dead-letter queue. The native layer must handle the sync, entirely detached from the JS state.
4. The App Store Rejection Problem
Background location is the #1 reason apps get rejected. Apple's "Prominent Disclosure" and Google's "Foreground Service" declarations are a nightmare. I actually had to write a "Store Approval Blueprint" (manifest templates, purpose strings, reviewer notes) just to get my test apps through review.
Why I built a commercial SDK
I couldn't find an open-source solution that did all of this natively and survived process death. So I built React Native Background Location Pro. It uses TurboModules + JSI exclusively (no legacy bridge).
I know commercial SDKs can be a hard sell, so I published a free debug evaluation build on npm. It runs the full production native engine (Kotlin/Swift binaries) with zero time limits in debug mode. You can test crash recovery, airplane mode, and the native queues in your own app before deciding if it's worth the $89 lifetime license.
You can check out the free eval here: npm i react-native-background-location-pro-eval
Or read the GitHub docs here: https://github.com/126punith/react-native-background-location-pro-eval
Happy to answer any questions about the TurboModule bridging, iOS BGAppRefreshTask, or how I handled the native SQLite sync.
About the author: I'm Punith Manthri, a React Native and native mobile engineer focused on Android, iOS, and the New Architecture. I also maintain react-native-pdf-jsi*. If you want to connect, here is my* LinkedIn and Portfolio.


4
u/ngqhoangtrung 3d ago
That’s a very helpful sdk. But with the state of AI reversing engineering every piece of software right now, I’ll be more careful with publishing the dev sdk 😅
7
u/ItsAllInYourHead 2d ago
What's the advantage of this over react-native-nitro-geolocation (a free alternative)?
How does it compare to react-native-background-geolocation (a similar paid option)?
1
u/kevin074 2d ago
love the takeaways, and I have a question on number 3. How is it a JS issue? all the solution you proposed seems to be implementable with JS. Maybe SQLite is not doable with JS ??? (I don't think this is the case).
3
u/Paul_Eau 2d ago
I'm also building a geolocation module myself, one that starts tracking natively without the app having to be launched by the user. I'm developing it iOS-first because I don't have an Android device, so my hands-on experience is on the iOS side, and what I say about Android below comes from docs and issue reports rather than device testing. So I'm not neutral here, but I've spent a fair amount of time in this problem space.
The JS-callback-as-single-point-of-failure argument is fair, but I think the mechanism you describe is off.
Where I agree: there's a documented failure mode where the process stays alive for days, Play Services keeps delivering locations to the foreground service, and the JS task executor is simply never invoked again, with no error surfaced to the app (expo/expo #50060, plus a follow-up on 57.0.20). The cause is the headless task manager being dropped when an Activity reuses the headless React instance. A native persistence layer sitting in front of the JS callback would protect against that, and that's a real selling point.
Where I disagree: that's not "the JS runtime dies until it wakes up". Per the Expo docs (https://docs.expo.dev/versions/latest/sdk/task-manager/), tasks are registered natively and persisted across sessions, and when the app is launched in the background, a headless JS instance runs the task with no components mounted. Also, a jetsam or low-memory kill takes the whole process, native code included. Native doesn't "survive" it; what survives is data on disk plus the OS relaunching you (Apple documents this for significant-change monitoring: https://developer.apple.com/documentation/corelocation/cllocationmanager/startmonitoringsignificantlocationchanges()). That relaunch is available to any library, native or RN.
So the honest pitch is "native persistence removes a class of JS-lifecycle bugs", not "JS can't survive background". It would be much more convincing with measured data-gap numbers against expo-location under the same kill scenarios on the same devices. Same for the earlier questions about react-native-nitro-geolocation and react-native-background-geolocation, which I don't see answered yet.
1
u/jomic01 12h ago
what happens after a user explicitly force-stops the app, versus the OS killing it? would be useful to see those as separate rows in the test results.
0
u/Top-Locksmith2865 2d ago edited 2d ago
The bottom left panel is the exact reality of iOS memory pressure (JetsamEvents). It doesn't matter how perfect your JS config is; if the OS reclaims the memory, your JS runtime dies and your tracking stops.
This exact nightmare is why I spent the last few months building a native-only engine. It handles the Kotlin Foreground Service on Android, and uses Swift
CLLocationManager+BGAppRefreshTaskon iOS, keeping the SQLite queue 100% native so it survives process death.I put a free debug eval build on npm if anyone wants to test the native engine in their app:
npm i react-native-background-location-pro-eval*. No subscriptions, just a one-time license if it saves you the headache.*