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

[Help Wanted] Background Location Not Updating Consistently + Offline Data Collection Issues on iOS & Android

Open karthikeyanthavamani opened this issue 6 months ago • 10 comments

Required Reading

  • [x] Confirmed

Plugin Version

"react-native-background-geolocation": "^4.18.6",

Mobile operating-system(s)

  • [x] iOS
  • [x] Android

Device Manufacturer(s) and Model(s)

moto edge 40 neo

Device operating-systems(s)

android 13

React Native / Expo version

react-native: 0.73.4

What do you require assistance about?

I'm using the licensed version of react-native-background-geolocation, and I'm encountering issues where latitude and longitude stop updating for long periods (30 minutes to 1 hour). I need help ensuring reliable background tracking, especially when the app is in the background or the device is offline.

🧪 Environment Library: react-native-background-geolocation (licensed)

Platform(s): Android & iOS

React Native Version: [insert here]

Device(s): [insert model(s)]

Permissions: Location Always, Background Modes enabled

🐞 Problem Description Background location updates stop intermittently.

This happens even when background mode is enabled and location permission is granted.

When the device is offline, location data is not collected or synced later.

On iOS, it's unclear how background updates behave, especially regarding battery optimizations.

[Optional] Plugin Code and/or Config

import BackgroundGeolocation from 'react-native-background-geolocation';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createLiveTracking } from './services/hsa.service';
import { Alert } from 'react-native';
import { startBackgroundTask } from './FlightModeAndLocation'
let lastUpdateTimestamp = 0;

export async function requestLocationPermission() {
    try {
        const state = await BackgroundGeolocation.requestPermission();
        return state === BackgroundGeolocation.AUTHORIZATION_STATUS_ALWAYS ||
            state === BackgroundGeolocation.AUTHORIZATION_STATUS_WHEN_IN_USE;
    } catch (error) {
        console.error('Error requesting location permission:', error);
        return false;
    }
}

export async function getCurrentLocation() {
    return new Promise((resolve, reject) => {
        BackgroundGeolocation.getCurrentPosition(
            {
                samples: 1,
                persist: false,
                timeout: 5000,
            },
            (location) => {
                resolve({
                    lat: location.coords.latitude,
                    lng: location.coords.longitude,
                });
            },
            (error) => {
                console.error('Location error:', error);
                if (error === 1) {
                    console.log('Permission issue: Requesting location access...');
                    requestLocationPermission();
                }
                reject(false);
            }
        );
    });
}

export async function startLocationTracing(payload) {
    try {
        const userId = await AsyncStorage.getItem('userId');
        if (!userId) {
            console.warn('User ID not found in storage.');
            return;
        }

        BackgroundGeolocation.ready({
            desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
            distanceFilter: 0,
            locationUpdateInterval: 10000,
            fastestLocationUpdateInterval: 10000,
            stopOnTerminate: false,
            startOnBoot: true,
            foregroundService: true,
            enableHeadless: true,
            heartbeatInterval: 10,
            allowIdenticalLocations: true,
            preventSuspend: true,
            locationAuthorizationRequest: 'Always',
            debug: false,
            logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
        }).then((state) => {
            if (!state.enabled) {
                BackgroundGeolocation.start().then(() => {
                    console.log("- Start success");
                    Alert.alert("Success", "BackgroundGeolocation started successfully!");
                }).catch((error) => {
                    console.error("- Start failed: ", error);
                });
            }
        });

        const handleLocationUpdate = async (eventType) => {
            const now = Date.now();
            if (now - lastUpdateTimestamp >= 10000) { // 10 seconds
                lastUpdateTimestamp = now;

                const location = await BackgroundGeolocation.getCurrentPosition({
                    samples: 1,
                    persist: false,
                });

                const data = {
                    latitude: location.coords.latitude,
                    longitude: location.coords.longitude,
                    user: userId,
                    dateTime: location.timestamp,
                    ...payload,
                };

                // console.log(`[${eventType}] Sending location data to server:`, data);
                await createLiveTracking(data);
                await AsyncStorage.setItem('locationPayload', JSON.stringify(payload));
                startBackgroundTask(payload);
            } else {
                // console.log(`[${eventType}] Skipped - Throttled`);
            }
        };

        BackgroundGeolocation.onHeartbeat(() => handleLocationUpdate('onHeartbeat'));
        BackgroundGeolocation.onMotionChange(() => handleLocationUpdate('onMotionChange'));
        BackgroundGeolocation.onLocation(() => handleLocationUpdate('onLocation'));

    } catch (error) {
        console.error('Error starting location tracing:', error);
    }
}

let locationInterval = null;

export function stopLocationTracing() {
    if (locationInterval) {
        clearInterval(locationInterval);
        locationInterval = null;
    }
    BackgroundGeolocation.stop();
    console.log('Location tracking stopped.');
}

[Optional] Relevant log output

// BackgroundGeolocationHeadlessTask.js
import BackgroundGeolocation from 'react-native-background-geolocation';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createLiveTracking } from './services/hsa.service';
import { startBackgroundTask } from './FlightModeAndLocation'

let lastUpdateTimestamp = 0;

const BackgroundGeolocationHeadlessTask = async (event) => {
    console.log('[HeadlessTask] Event:', event.name);

    switch (event.name) {
        case 'heartbeat':
        case 'location':
        case 'motionchange':
            try {
                startBackgroundTask();
                const userId = await AsyncStorage.getItem('userId');
                if (!userId) {
                    console.warn('Headless: No user ID found.');
                    return;
                }

                const now = Date.now();
                if (now - lastUpdateTimestamp < 10000) return; // Throttle to 10 seconds
                lastUpdateTimestamp = now;

                let location = event.params;

                // If location is not passed with the event (e.g., heartbeat), manually fetch it
                if (!location || !location.coords) {
                    console.log('[Headless] Fetching current position...');
                    location = await BackgroundGeolocation.getCurrentPosition({
                        samples: 1,
                        persist: false,
                        timeout: 5000,
                    });
                }

                const data = {
                    latitude: location.coords.latitude,
                    longitude: location.coords.longitude,
                    user: userId,
                    dateTime: location.timestamp,
                };

                console.log('[Headless] Sending to server:', data);
                await createLiveTracking(data);
            } catch (error) {
                console.error('[Headless] Error:', error);
            }
            break;

        default:
            console.log('[Headless] Unhandled event:', event.name);
    }
};


export default BackgroundGeolocationHeadlessTask;

karthikeyanthavamani avatar Jun 06 '25 07:06 karthikeyanthavamani