react-native-background-geolocation icon indicating copy to clipboard operation
react-native-background-geolocation copied to clipboard

[Help Wanted]: Delay in First Location Update After Starting Trip – Takes 30 Seconds

Open Jaimin2603 opened this issue 6 months ago • 5 comments

Required Reading

  • [x] Confirmed

Plugin Version

"react-native-background-geolocation": "^4.18.7"

Mobile operating-system(s)

  • [x] iOS
  • [ ] Android

Device Manufacturer(s) and Model(s)

iPhone 15 Plus

Device operating-systems(s)

iOS 18.5

React Native / Expo version

0.74.1

What do you require assistance about?

Subject: iOS 18.1 – 30-Second Delay for First Location Update Despite All Permissions Granted (Logs #Attached)

I am experiencing a significant delay in receiving the first location update after starting a trip using the background geolocation plugin. Specifically, it takes around 30 seconds for the first update to be received, which is affecting the user experience.

Details: Issue: After starting a trip, the first location update is delayed by about 30 [seconds.]

Expected: The first location update should be received much sooner after starting the trip.

Observed: As shown in the attached logs, there is a gap of approximately 30 seconds between the initial trip start and the next location update.

Log Evidence: At "formatted_datetime": "06-06-2025 10:43:37 AM", the trip starts and the first location is logged.

The next significant location update does not occur until "formatted_datetime": "06-06-2025 10:44:06 AM", which is about 30 seconds later.

This gap is consistent and reproducible. Here is the log while tracking.

        {
            "formatted_datetime": "06-06-2025 10:43:37 AM",
            "output_log": {
                "odometer": 20.9,
                "event": "motionchange",
                "age": 837,
                "uuid": "8D3E4919-E52E-4C91-98F7-9832B17966A4",
                "is_moving": false,
                "timestamp": "2025-06-06T10:43:37.018Z",
                "coords": {
                    "altitude": 38.84,
                    "latitude": 22.69163226710883,
                    "heading": 213.4,
                    "altitude_accuracy": 3,
                    "heading_accuracy": 52.68,
                    "ellipsoidal_altitude": -17.78,
                    "accuracy": 14,
                    "speed_accuracy": 0.73,
                    "longitude": 72.8616261017256,
                    "speed": 0.46,
                    "floor": null
                },
                "extras": {},
                "battery": {
                    "is_charging": false,
                    "level": 0.6499999761581421
                },
                "activity": {
                    "confidence": 100,
                    "type": "unknown"
                }
            }
        },
        {
            "formatted_datetime": "06-06-2025 10:43:37 AM",
            "output_log": {
                "odometer": 20.9,
                "age": 0,
                "uuid": "54973471-01CF-41E0-BAF6-4D453FBE4655",
                "is_moving": false,
                "sample": true,
                "extras": {},
                "timestamp": "2025-06-06T10:43:37.846Z",
                "coords": {
                    "altitude": 38.84,
                    "latitude": 22.69163226710883,
                    "heading": 213.4,
                    "altitude_accuracy": 3,
                    "heading_accuracy": 52.68,
                    "ellipsoidal_altitude": -17.78,
                    "accuracy": 14,
                    "speed_accuracy": 0.73,
                    "longitude": 72.8616261017256,
                    "speed": 0.46,
                    "floor": null
                },
                "battery": {
                    "is_charging": false,
                    "level": -1
                },
                "activity": {
                    "confidence": 100,
                    "type": "unknown"
                }
            }
        },
        {
            "formatted_datetime": "06-06-2025 10:44:06 AM",
            "output_log": {
                "odometer": 20.9,
                "age": 0,
                "uuid": "1CA8503F-6C41-495E-A59E-BF585E40EE5D",
                "is_moving": true,
                "sample": true,
                "extras": {},
                "timestamp": "2025-06-06T10:44:06.216Z",
                "coords": {
                    "altitude": 39.54,
                    "latitude": 22.691409957792207,
                    "heading": -1,
                    "altitude_accuracy": 30,
                    "heading_accuracy": -1,
                    "ellipsoidal_altitude": -17.08,
                    "accuracy": 6.86,
                    "speed_accuracy": -1,
                    "longitude": 72.86182643809002,
                    "speed": -1,
                    "floor": null
                },
                "battery": {
                    "is_charging": false,
                    "level": 0.6499999761581421
                },
                "activity": {
                    "confidence": 100,
                    "type": "on_foot"
                }
            }
        },
        {
            "formatted_datetime": "06-06-2025 10:44:06 AM",
            "output_log": {
                "odometer": 53,
                "event": "motionchange",
                "age": 34,
                "uuid": "010C0113-8A26-48EB-8746-D822CFA14F09",
                "is_moving": true,
                "timestamp": "2025-06-06T10:44:06.196Z",
                "coords": {
                    "altitude": 39.54,
                    "latitude": 22.691409957792207,
                    "heading": -1,
                    "altitude_accuracy": 30,
                    "heading_accuracy": -1,
                    "ellipsoidal_altitude": -17.08,
                    "accuracy": 6.86,
                    "speed_accuracy": -1,
                    "longitude": 72.86182643809002,
                    "speed": -1,
                    "floor": null
                },
                "extras": {},
                "battery": {
                    "is_charging": false,
                    "level": 0.6499999761581421
                },
                "activity": {
                    "confidence": 100,
                    "type": "on_foot"
                }
            }
        },
        {
            "formatted_datetime": "06-06-2025 10:44:08 AM",
            "output_log": {
                "odometer": 53,
                "age": 37,
                "uuid": "EBED245A-ED37-4401-B7E5-B14AE5E977E9",
                "is_moving": true,
                "timestamp": "2025-06-06T10:44:08.000Z",
                "coords": {
                    "altitude": 38.63,
                    "latitude": 22.691388856640728,
                    "heading": 169.1,
                    "altitude_accuracy": 8,
                    "heading_accuracy": 58.19,
                    "ellipsoidal_altitude": -17.98,
                    "accuracy": 14,
                    "speed_accuracy": 0.8,
                    "longitude": 72.86181259907117,
                    "speed": 0.7,
                    "floor": null
                },
                "extras": {},
                "battery": {
                    "is_charging": false,
                    "level": 0.6499999761581421
                },
                "activity": {
                    "confidence": 100,
                    "type": "on_foot"
                }
            }
        },
        {
            "formatted_datetime": "06-06-2025 10:44:09 AM",
            "output_log": {
                "odometer": 53,
                "age": 35,
                "uuid": "4C80ADE1-53FA-406B-954C-BEF8879EAB0F",
                "is_moving": true,
                "timestamp": "2025-06-06T10:44:09.000Z",
                "coords": {
                    "altitude": 39.53,
                    "latitude": 22.69137649333355,
                    "heading": 171.91,
                    "altitude_accuracy": 8,
                    "heading_accuracy": 72.66,
                    "ellipsoidal_altitude": -17.09,
                    "accuracy": 14,
                    "speed_accuracy": 0.89,
                    "longitude": 72.86180723465314,
                    "speed": 0.7,
                    "floor": null
                },
                "extras": {},
                "battery": {
                    "is_charging": false,
                    "level": 0.6499999761581421
                },
                "activity": {
                    "confidence": 100,
                    "type": "on_foot"
                }
            }
        },
        {
            "formatted_datetime": "06-06-2025 10:44:10 AM",
            "output_log": {
                "odometer": 58.7,
                "age": 57,
                "uuid": "476EC24F-CF9A-4A66-A62B-8259C9CE4157",
                "is_moving": true,
                "timestamp": "2025-06-06T10:44:10.000Z",
                "coords": {
                    "altitude": 39.17,
                    "latitude": 22.691365429221364,
                    "heading": 168.05,
                    "altitude_accuracy": 6,
                    "heading_accuracy": 54.73,
                    "ellipsoidal_altitude": -17.45,
                    "accuracy": 4.44,
                    "speed_accuracy": 0.78,
                    "longitude": 72.861798936569,
                    "speed": 0.7,
                    "floor": null
                },
                "extras": {},
                "battery": {
                    "is_charging": false,
                    "level": 0.6499999761581421
                },
                "activity": {
                    "confidence": 100,
                    "type": "on_foot"
                }
            }
        },
        {
            "formatted_datetime": "06-06-2025 10:44:11 AM",
            "output_log": {
                "odometer": 58.7,
                "age": 33,
                "uuid": "B0EBB294-04A3-4258-8FBF-75AAFF68679D",
                "is_moving": true,
                "timestamp": "2025-06-06T10:44:11.000Z",
                "coords": {
                    "altitude": 39.06,
                    "latitude": 22.691353401190312,
                    "heading": 179.3,
                    "altitude_accuracy": 6,
                    "heading_accuracy": 49.59,
                    "ellipsoidal_altitude": -17.56,
                    "accuracy": 4.45,
                    "speed_accuracy": 0.83,
                    "longitude": 72.86179122521808,
                    "speed": 0.75,
                    "floor": null
                },
                "extras": {},
                "battery": {
                    "is_charging": false,
                    "level": 0.6499999761581421
                },
                "activity": {
                    "confidence": 100,
                    "type": "on_foot"
                }
            }
        },
        {
            "formatted_datetime": "06-06-2025 10:44:12 AM",
            "output_log": {
                "odometer": 58.7,
                "age": 34,
                "uuid": "298461E9-105C-482A-831A-0651BED5F105",
                "is_moving": true,
                "timestamp": "2025-06-06T10:44:12.000Z",
                "coords": {
                    "altitude": 38.52,
                    "latitude": 22.69134179225442,
                    "heading": 184.57,
                    "altitude_accuracy": 6,
                    "heading_accuracy": 47.33,
                    "ellipsoidal_altitude": -18.09,
                    "accuracy": 4.33,
                    "speed_accuracy": 0.82,
                    "longitude": 72.86178376532426,
                    "speed": 0.98,
                    "floor": null
                },
                "extras": {},
                "battery": {
                    "is_charging": false,
                    "level": 0.6499999761581421
                },
                "activity": {
                    "confidence": 100,
                    "type": "on_foot"
                }
            }
        },
        {
            "formatted_datetime": "06-06-2025 10:44:13 AM",
            "output_log": {
                "odometer": 63,
                "age": 36,
                "uuid": "CAE8C240-A8D9-4B10-8249-F546FB2C1B77",
                "is_moving": true,
                "timestamp": "2025-06-06T10:44:13.000Z",
                "coords": {
                    "altitude": 37.78,
                    "latitude": 22.691331692061098,
                    "heading": 190.55,
                    "altitude_accuracy": 6,
                    "heading_accuracy": 49.22,
                    "ellipsoidal_altitude": -18.84,
                    "accuracy": 4.04,
                    "speed_accuracy": 0.78,
                    "longitude": 72.86177689216366,
                    "speed": 0.98,
                    "floor": null
                },
                "extras": {},
                "battery": {
                    "is_charging": false,
                    "level": 0.6499999761581421
                },
                "activity": {
                    "confidence": 100,
                    "type": "on_foot"
                }
            }
        }
    ] ```

### [Optional] Plugin Code and/or Config

```typescript

[Optional] Relevant log output


Jaimin2603 avatar Jun 06 '25 11:06 Jaimin2603

This is my code that I used for tracking the trip

const warmUpBackgroundGeolocation = async () => {
    try {
      await BackgroundGeolocation.ready(
        {
          desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_LOW,
          distanceFilter: 100, // Large value to minimize battery use
          stationaryRadius: 50,
          locationUpdateInterval: 60000, // 1 minute
          fastestLocationUpdateInterval: 30000,
          stopOnStationary: true,
          locationAuthorizationRequest: 'WhenInUse',
          allowsBackgroundLocationUpdates: false,
          pausesLocationUpdatesAutomatically: true,
          debug: false,
          stopOnTerminate: false,
          startOnBoot: false,
          foregroundService: false,
          enableHeadless: false,
        },
        state => {
          if (!state.enabled) {
            BackgroundGeolocation.start();
          }
        },
      );
    } catch (error) {
      console.error('Error warming up background geolocation:', error);
      sendErrorReport(error, 'warmup_bg_geolocation_error');
    }
  };

  // Keep GPS warm with periodic checks
  useEffect(() => {
    let intervalId;
    if (!isTimerStart && !isPause) {
      intervalId = setInterval(() => {
        getCurrentLocation();
      }, 30000); // Every 30 seconds
    }
    return () => clearInterval(intervalId);
  }, [isTimerStart, isPause]);

  useEffect(() => {
    getCurrentLocation();
    warmUpBackgroundGeolocation();
  }, []);

  // Initialize BackgroundGeolocation
  const initializeBackgroundGeolocation = async () => {
    if (isInitializingRef.current) return;
    isInitializingRef.current = true;

    try {
      await BackgroundGeolocation.setConfig({
        desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
        distanceFilter: 1,
        stationaryRadius: 2,
        locationUpdateInterval: 1000,
        fastestLocationUpdateInterval: 500,
        activityRecognitionInterval: 1000,
        disableMotionActivityUpdates: false,
        stopOnStationary: true,
        preventSuspend: true,
        locationAuthorizationRequest: 'Always',
        allowsBackgroundLocationUpdates: true,
        pausesLocationUpdatesAutomatically: false,
        showsBackgroundLocationIndicator: true,
        debug: false,
        stopOnTerminate: false,
        startOnBoot: true,
        foregroundService: true,
        enableHeadless: true,
        activityType: BackgroundGeolocation.ACTIVITY_TYPE_OTHER_NAVIGATION,
      });

      // Ensure tracking is started in moving state
      BackgroundGeolocation.start({isMoving: true});

      // Set up location listener
      await BackgroundGeolocation.onLocation(
        location => {
          updatePosition(location.coords);
          sendErrorReport(location, 'onLocation_trip_tracking');
        },
        error => {
          console.log('[onLocation] ERROR:', error);
          sendErrorReport(error, 'onLocation_error_trip_tracking');
        },
      );

      isInitializingRef.current = false;
    } catch (error) {
      sendErrorReport(error, 'init_bg_geolocation_error');
      isInitializingRef.current = false;
    }
  };

  // Calculate distance between two points in meters
  const getDistance = (point1, point2) => {
    const R = 6371e3; // Earth's radius in meters
    const φ1 = (point1.latitude * Math.PI) / 180;
    const φ2 = (point2.latitude * Math.PI) / 180;
    const Δφ = ((point2.latitude - point1.latitude) * Math.PI) / 180;
    const Δλ = ((point2.longitude - point1.longitude) * Math.PI) / 180;

    const a =
      Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
      Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

    return R * c; // Distance in meters
  };

  const updatePosition = useCallback(
    debounce(position => {
      const {latitude, longitude, heading, speed, accuracy} = position;
      const newCoordinate = {latitude, longitude};
      sendErrorReport(heading, 'heading_location_update');
      sendErrorReport(speed, 'speed_locationn_update');
      const currentTime = Date.now();

      // Filter low-accuracy locations
      if (accuracy > 20) {
        console.log('Ignoring location: low accuracy', accuracy);
        return;
      }

      // Update user heading if available
      if (heading >= 0) {
        setUserHeading(heading);
      } else if (lastSavedPosition.current) {
        const calculatedHeading = calculateBearing(
          lastSavedPosition.current,
          newCoordinate,
        );
        setUserHeading(calculatedHeading);
      }

      // Handle speed from GPS
      if (speed === -1) {
        setAverageSpeed(0);
      } else {
        const speedKmh = speed * 3.6;
        setAverageSpeed(speedKmh);
      }

      if (!lastSavedPosition.current) {
        lastSavedPosition.current = newCoordinate;
        lastUpdateTime.current = currentTime;
        setStartTime(currentTime);
        saveNewCoordinate(newCoordinate, 'initial');
        setCurrentPosition(newCoordinate);
        setRegion({
          latitude: newCoordinate.latitude,
          longitude: newCoordinate.longitude,
          latitudeDelta: 0.0009,
          longitudeDelta: 0.0009,
        });
        return;
      }

      // Calculate distance between last saved position and new position
      const distanceInMeters = getDistance(
        lastSavedPosition.current,
        newCoordinate,
      );
      sendErrorReport(distanceInMeters, 'distanceInMeters_location_update');
      if (distanceInMeters > 1) {
        // Only update if moved more than 2 meters
        const distance = tripDistance + distanceInMeters;
        sendErrorReport(distance, 'distance_update');
        dispatch(setTripDistance(distance));
        lastSavedPosition.current = newCoordinate;
        lastSavedPosition.current = newCoordinate;
        saveNewCoordinate(newCoordinate, 'update');
        setCurrentPosition(newCoordinate);
        setRegion(prev => ({
          latitude: newCoordinate.latitude,
          longitude: newCoordinate.longitude,
          latitudeDelta: prev?.latitudeDelta || 0.0009,
          longitudeDelta: prev?.longitudeDelta || 0.0009,
        }));
      }
    }, 100),
    [tripDistance, startTime, isLandscape, averageSpeed],
  );

  // Clean up BackgroundGeolocation
  const cleanupBackgroundGeolocation = async () => {
    try {
      await BackgroundGeolocation.stop();
      await BackgroundGeolocation.removeListeners();
      console.log('BackgroundGeolocation stopped and listeners removed');
    } catch (error) {
      console.error('Error cleaning up BackgroundGeolocation:', error);
      sendErrorReport(error, 'cleanup_bg_geolocation_error');
    }
  };

  useEffect(() => {
    if (isTimerStart && !isPause) {
      initializeBackgroundGeolocation();
      BackgroundGeolocation.getCurrentPosition({
        persist: false,
        samples: 1,
        timeout: 30, // seconds
        maximumAge: 1000,
        desiredAccuracy: 10,
      })
        .then(location => {
          console.log('[getCurrentPosition]', location);
          // Optional: show "trip started" indicator now
        })
        .catch(error => {
          console.warn('[getCurrentPosition] ERROR', error);
        });
    } else {
      cleanupBackgroundGeolocation();
    }

    return () => {
      cleanupBackgroundGeolocation();
    };
  }, [isTimerStart, isPause]);```

Jaimin2603 avatar Jun 06 '25 11:06 Jaimin2603

Please learn to syntax highlight multiline code blocks. Edit your post.

The issue template provided fields to post your Config/Code into so it could automatically syntax highlight for you, but you just ignored that.

https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks

christocracy avatar Jun 06 '25 11:06 christocracy

The Code format has been edited. Please review it and provide an update.

Jaimin2603 avatar Jun 06 '25 11:06 Jaimin2603

There's so much wrong with your code.

  1. Read the Philosophy of Operation, especially the following section: Image

  2. Also read the API docs Config.stationaryRadius

To transition from the stationary state -> moving state, an iOS device must move at least 200 meters. Or you manually execute .changePace(true) while your app is in the foreground.

  1. You must NEVER call any method which accesses the location API (eg: .getCurrentPosition) **before calling .ready(config), as warned in the README
useEffect(() => {
    getCurrentLocation();   // <----------- NO!  NO!  NO!  NO!  NO!
    warmUpBackgroundGeolocation();
  }, []);
  1. Always register event-listeners BEFORE calling .ready(config).
  2. You are not required to add event-listeners each time you call .start() and remove them when calling .stop(). Event listeners are like speakers of a stereo system — Do you disconnect your speakers each time your turn off your stereo system?? No! People connect their speakers forever. Subscribe to event-listeners once (before calling .ready(config) for the entire life-time of your app. They are harmless, nothing more than a Function held in an Array.
  3. Learn to observe the plugin's incredibly verbose logging system, configure for verbose logging and use the debug: true feature. See Wiki "Debugging"

christocracy avatar Jun 06 '25 13:06 christocracy

Issue: After starting a trip, the first location update is delayed by about 30 [seconds.]

The "gap" you're talking about is expressed in this screenshot from the API docs Config.stationaryRadius (see the green polylines). This is the 200 meters of movement before the plugin automatically transitions to the moving state. All of this is normal and expected behaviour. As mentioned above, if you want to manually initiate tracking immediately, call the method .changePace(true).

Image

In the Demo App, the green play / pause button in the bottom toolbar executes .changePace(true) / .changePace(false) (like a music player).

Image

christocracy avatar Jun 06 '25 13:06 christocracy

This issue is stale because it has been open for 30 days with no activity.

github-actions[bot] avatar Jul 07 '25 02:07 github-actions[bot]

This issue was closed because it has been inactive for 14 days since being marked as stale.

github-actions[bot] avatar Jul 21 '25 02:07 github-actions[bot]