transistorsoft / transistorsoft/react-native-background-geolocation

[Bug]: iOS: relaunch from terminated state via stationary-region exit leaves tracker blind until stopTimeout

Open
#2,661 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
2.9k
Forks
446
PR merge metrics
No merged PRs in 30d

Description

Required Reading
  • Confirmed
Plugin Version

react-native-background-geolocation 5.6.0

Mobile operating-system(s)
  • iOS
  • Android
Device Manufacturer(s) and Model(s)

iPhone 11

Device operating-systems(s)

iOS 26.2.1

React Native / Expo version

0.86.3, Expo SDK 57

What happened?

Expected Behavior
After the app is terminated by the user and iOS relaunches it in the background because the device exits the stationary region, the plugin should process the didUpdateLocations callbacks CoreLocation delivers after start() and emit location events to JS.

Actual Behavior
When the very first CoreLocation callback the plugin receives after relaunch is locationManager:didExitRegion: (delivered ~30 ms after TSLocationManager init, i.e. before ready() and before start()), the plugin switches to isMoving = 1 and calls startUpdatingLocation, but from then on it silently discards every location. CoreLocation invokes the plugin's CLLocationManager delegate with didUpdateLocations: ~40 times over the next 2 minutes; the plugin logs zero TSLocationFilter evaluateWithMetrics: lines, persists nothing, and emits no location/motionchange events to JS. Only the single cached fix returned by getCurrentPosition() at startup reaches JS.
The plugin only recovers when its own stopTimeout fires 300 s later (onStopTimeout → changePace: isMoving 0), after which locations are evaluated normally.
Reproduced 4 of 4 times when the relaunch is triggered by the region exit. When the app happened to be relaunched by another locationd event while still inside the region (2 runs), didExitRegion arrived 30 s later, after ready()/start(), and tracking worked perfectly (10/10 geofenced alerts).

Steps to Reproduce
Fresh install, grant Always + Motion, ready() + start() in foreground, leave the device stationary so the plugin creates its stationary region.
Terminate the app from the app switcher.
Move the device (we used Xcode/pymobiledevice3 location simulation, a 1.9 km route at 50 km/h, one fix every 3 s; the device itself is physically still on a desk, so CMMotionActivity reports stationary).
~30 s later iOS relaunches the app (OpenApplication ForRequester(locationd), intent background) because of the region exit.
Observe: didExitRegion handled before ready; no locations evaluated until stopTimeout fires.

Plugin Code and/or Config
Config (relevant): desiredAccuracy High, distanceFilter 10, stationaryRadius 25 (SDK enforces 150), stopTimeout 5, stopOnTerminate false, startOnBoot true, activityType Other, locationAuthorizationRequest Any, pausesLocationUpdatesAutomatically default (true), preventSuspend false, no heartbeat. Location permission: Always. Motion & Fitness: granted.
Relevant log output
Plugin log (bad run, relaunched by region exit) — from the device syslog, plugin + CoreLocation categories
13:39:48.609 -[TSLocationManager init]
13:39:48.630 CoreLocation: invoking delegate locationManager:didExitRegion:  (manager 0x15864dc50)
13:39:48.637 CoreLocation: invoking delegate locationManager:didExitRegion:  (manager 0x15864d8a0)
13:39:48.637 -[TSTrackingService locationManager:didExitRegion:] Exit stationary region
13:39:48.637 -[TSTrackingService changePace:] isMoving: 1
13:39:48.657 -[TSTrackingService startUpdatingLocation] Location-services: ON
13:39:48.661 -[TSTrackingService locationManager:didUpdateLocations:] <IGNORED> Δt since last: -357285 ms
13:39:48.806 -[TSLocationManager ready]
13:39:49.415 -[TSLocationManager ready]_block_invoke Booted in background
13:39:49.415 -[TSTrackingService start:] [start] desiredPolicy=2 status=3 didRequestUpgrade=1 isAuthorizedForPolicy=1
13:39:49.417 -[TSTrackingService changePace:] isMoving: 1
13:39:49.436 -[TSTrackingService startUpdatingLocation] Location-services: ON
13:39:49.451 -[TSTrackingService beginStopDetection] Stop-timeout engaged: 300 s...
... CoreLocation delivers didUpdateLocations: to manager 0x15864d8a0 41 times between 13:39:48 and 13:41:50 ...
... plugin: 0 x "TSLocationFilter evaluateWithMetrics", 0 x "📍<lat,lon>", 0 x TSDataStore INSERT type 1, 0 events to JS ...
13:44:49.4  -[TSTrackingService onStopTimeout] 🛑 stopTimeout fired
13:44:49.4  -[TSTrackingService changePace:] isMoving: 0
           (from here on, locations are evaluated and emitted normally)


Plugin log (good run, relaunched while still inside the region) — for comparison
13:07:10.393 -[TSLocationManager init]
13:07:10.570 -[TSLocationManager ready]
13:07:11.200 -[TSLocationManager ready]_block_invoke Booted in background
13:07:11.200 -[TSTrackingService start:] [start] desiredPolicy=2 status=3 ...
13:07:11.201 -[TSTrackingService changePace:] isMoving: 0
13:07:11.318 -[TSTrackingService onUpdateState:] Is location beyond stationaryRadius? Δd: 0.0, radius: 150.0
13:07:40.126 -[TSTrackingService locationManager:didExitRegion:] Exit stationary region
13:07:40.127 -[TSTrackingService changePace:] isMoving: 1
13:07:43.158 -[TSLocationFilter evaluateWithMetrics:] decision=Accepted ...   (and every 3 s after)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with TSTrackingService locationManager:didExitRegion:, startUpdatingLocation, and didUpdateLocations:, comparing the bad and good callback ordering around TSLocationManager ready and start. Reproduce the terminated-app region-exit flow using the documented iPhone and simulated route, then verify that delivered locations are evaluated, persisted, and emitted to JS before stopTimeout fires.

Written by the indexing model from the issue text.

Assessment

Tech stack
ios, react-native, typescript
Domain
mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.