feat(ios): native location watch relayed through JS - #29677
Merged
chrisnojima merged 7 commits intoSep 23, 2026
Merged
Conversation
iOS live location runs on a CLLocationManager in the react-native-kb module instead of the expo-location background task. JS still answers the service's chatWatchPosition/chatClearWatch, refcounts the native watch, and forwards fixes with localLocationUpdate. Native only applies a 65 m distanceFilter and emits every fix; JS throttles out of the foreground (a move must exceed both fixes' accuracies summed, clamped to 65-200 m, or be a fix more than twice as sharp), restarting the throttle with each watch. The throttle's jest table ports the go/chat/maps throttle cases. The legacy expo task is unregistered at startup so expo stops restoring a second location manager. Android keeps the expo-location path.
…ix while active Significant-change monitoring survives termination and keeps relaunching the app, and the service drops an expired share without clearing its watch, so JS init now stops the native watch before the engine can deliver a restored chatWatchPosition. Native stop creates the manager if needed and always stops both update streams when the watch is not wanted. The native distance filter is off while the app is active (every fix, as the expo path reported) and 65 m otherwise, following the lifecycle state native already reports. The clear-watch refcount no longer goes negative, and a restarted watch drops any fix listener a failed stop left behind.
chrisnojima
added this pull request to stack #29680
September 23, 2026 19:54
chrisnojima
removed this pull request from stack #29680
September 23, 2026 19:56
chrisnojima
added this pull request to stack #29681
September 23, 2026 19:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack 5/7 on #29650.
Why
chatClearWatchpushed the watch refcount below zero, so the next share never started the OS watch.What this changes
KbLocationWatcherwrapsCLLocationManager. It enables background updates and significant-change monitoring, and exposesstartLocationWatch/stopLocationWatchand anonLocationFixevent, and the pod adds CoreLocation. The distance filter follows the app lifecycle from the first PR in this stack.chatWatchPosition/chatClearWatchdrive the native watch, and the refcount can no longer go below zero.shouldRecordFix, thenlocalLocationUpdate.Judgment calls
distanceFilteris None while the app is active and 65 m otherwise. That keeps master's every-fix behaviour on screen.launchOptions[.location]). Without one, each background relaunch while a killed share lingers costs one Go init and a launch flush.LocationUpdatealready moves BACKGROUND to BACKGROUNDACTIVE.Tests
location-throttle.test.tsports the Go throttle table and its sequence tests: jitter, slow drift, outlier anchor, coarse anchor. It also adds a case for the half-accuracy clause.location-watch.test.tscovers:resultbefore startMutation-checked.