Skip to content

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

Description

@AdrianMerida

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)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions