transistorsoft / react-native-background-geolocation

Sophisticated, battery-conscious background-geolocation with motion-detection
http://shop.transistorsoft.com/pages/react-native-background-geolocation
MIT License
2.66k stars 426 forks source link

Tried to start task BackgroundGeolocation #2132

Closed jabal3amel closed 1 month ago

jabal3amel commented 2 months ago

the problem is the location is stop and start frequently every time he send location get me notification 'location tracking is active ' this notification appear for a few seconds and hide quickly


////////////////////////////////////////////////////////////////////////////////////////

//this code is for run code in foreground and in background 

import React, { createContext, useContext, useState } from 'react';
import { Platform, PermissionsAndroid, DeviceEventEmitter } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import BackgroundGeolocation from 'react-native-background-geolocation';
import moment from 'moment';
import Api from '../../util/api';
import ApiMethod from '../../util/ApiMethod';
import NetInfo from '@react-native-community/netinfo';
import simplify from 'simplify-js';
import WorkManager from '../WorkManager';
import messaging from '@react-native-firebase/messaging';

let wsRef = null;
let isConnected = false;
const TrackingContext = createContext();
export const useTracking = () => {
    return useContext(TrackingContext);
};

const TrackingComponent = ({ children }) => {
    let lastLocationTimestamp = 0;
    let currentTaskType = 'onLocation';
    let eventListenerSubscription = null;
    const MIN_LOCATION_INTERVAL = 3000; // Minimum interval (3 seconds) between location updates
    const [location, setLocation] = useState();
    const StopTracking = async () => {
        try {
            getLogs();
            await AsyncStorage.removeItem('appLogs');

            const netinfo = await NetInfo.fetch();
            isConnected = netinfo.isConnected;

            await BackgroundGeolocation.getState(async state => {
                const tolerance = 0.001;
                const highQuality = true;

                if (state.enabled) {
                    await BackgroundGeolocation.removeListeners();
                    await BackgroundGeolocation.removeAllListeners();
                    await BackgroundGeolocation.stop();
                    await WorkManager.CancelWork();
                    await unsubscribeFromTopic();
                    await AsyncStorage.setItem('tracking', 'false');

                    if (wsRef) {
                        await wsRef.close();
                        wsRef = null;
                    }

                    const storedPoints = await AsyncStorage.getItem('tracking_points');
                    const pointsArray = storedPoints ? JSON.parse(storedPoints) : [];
                    console.log('pointsArray:', pointsArray.length);

                    const simplifiedPoints = simplify(pointsArray, tolerance, highQuality);
                    console.log('Simplified Points:', simplifiedPoints.length);

                    if (isConnected) {
                        const response = await sendPointsToServer(simplifiedPoints);
                        console.log('sendPointsToServer', response);

                        if (response) {
                            await AsyncStorage.removeItem('tracking_points');
                        } else {
                            await AsyncStorage.setItem('tracking_points', JSON.stringify(simplifiedPoints));
                        }
                    } else {
                        await AsyncStorage.setItem('tracking_points', JSON.stringify(simplifiedPoints));
                    }
                }
            });
        } catch (error) {
            console.error('Error during StopTracking:', error);
        }
    };

    async function requestUserPermission() {
        const authStatus = await messaging().requestPermission();
        const enabled =
            authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
            authStatus === messaging.AuthorizationStatus.PROVISIONAL;

        if (!enabled) {
            console.log('Authorization status:', authStatus);
        }
    }

    const unsubscribeFromTopic = async () => {
        const isSubscribed = (await AsyncStorage.getItem('isSubscribedToUserTopic')) === 'true';

        let personString = await AsyncStorage.getItem('person');
        const person = await JSON.parse(personString);

        if (isSubscribed && person?.id) {
            await messaging()
                .unsubscribeFromTopic(`user_${person?.id}`)
                .then(async () => {
                    await AsyncStorage.setItem('isSubscribedToUserTopic', 'false');
                    console.log('unSubscribed to user topic');
                })
                .catch(error => console.error('Error unsubscribing from topic:', error));
        }
    };

    const subscribeToTopic = async () => {
        const isSubscribed = (await AsyncStorage.getItem('isSubscribedToUserTopic')) === 'true';

        let personString = await AsyncStorage.getItem('person');
        const person = await JSON.parse(personString);

        if (!isSubscribed && person?.id) {
            await messaging()
                .subscribeToTopic(`user_${person.id}`)
                .then(async () => {
                    await AsyncStorage.setItem('isSubscribedToUserTopic', 'true');
                    console.log('Subscribed to user topic');
                })
                .catch(error => console.error('Error subscribing to topic:', error));
        } else {
            console.log('Already subscribed to topic allUsers');
        }
    };

    const StartTracking = async () => {
        isConnected = true;
        await subscribeToTopic();
        await AsyncStorage.setItem('tracking', 'true');
        await initialize();
    };

    const initialize = async () => {
        const tracking = (await AsyncStorage.getItem('tracking')) === 'true';

        if (tracking) {
            await requestUserPermission();
            await requestPermissions();
            await requestLocationPermission();
            await configureBackgroundGeolocation();
        }
    };

    const requestPermissions = async () => {
        if (Platform.OS === 'android') {
            try {
                await PermissionsAndroid.requestMultiple([
                    PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
                    PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION,
                    PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION,
                ]);
            } catch (err) {
                console.warn(err);
            }
        }
    };

    const requestLocationPermission = async () => {
        if (Platform.OS === 'android') {
            const fineLocationGranted = await PermissionsAndroid.request(
                PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
                {
                    title: 'Location Access Required',
                    message: 'This App needs to Access your location',
                    buttonNeutral: 'Ask Me Later',
                    buttonNegative: 'Cancel',
                    buttonPositive: 'OK',
                }
            );

            if (fineLocationGranted !== PermissionsAndroid.RESULTS.GRANTED) {
                // console.log('Fine location permission denied');
                return;
            }

            if (Platform.Version >= 29) {
                const backgroundLocationGranted = await PermissionsAndroid.request(
                    PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION,
                    {
                        title: 'Background Location Access Required',
                        message: 'This app needs to access your location in the background',
                    }
                );

                if (backgroundLocationGranted !== PermissionsAndroid.RESULTS.GRANTED) {
                    // console.log('Background location permission denied');
                }
            }
        }
    };

    const scheduleNotification = () => {
        const interval = 10;
        WorkManager.schedulePeriodicWork(interval);
    };

    const configureBackgroundGeolocation = async () => {
        try {
            // Ensure previous listeners are removed
            await BackgroundGeolocation.removeListeners();
            await BackgroundGeolocation.removeAllListeners();
            await BackgroundGeolocation.stop();
            await WorkManager.CancelWork();
            if (eventListenerSubscription) {
                await eventListenerSubscription.remove();
                DeviceEventEmitter.removeAllListeners('livelocationapp');
                console.log('Event listener removed');
            }
            DeviceEventEmitter.addListener('livelocationapp', async () => {
                const now = Date.now();

                // Throttle updates to every 3 seconds
                if (now - lastLocationTimestamp < MIN_LOCATION_INTERVAL) {
                    logToAsyncStorage('Skipping location update to avoid excessive renders [onHeartbeat]');

                    console.log('Skipping location update to avoid excessive renders [onHeartbeat]');
                    return;
                }
                lastLocationTimestamp = now;

                currentTaskType = 'onHeartbeat';

                const location = await BackgroundGeolocation.getCurrentPosition({
                    timeout: 30,
                    maximumAge: 500,
                    desiredAccuracy: 5,
                    samples: 5,
                });

                console.log(`[onForeground] Running Task: ${currentTaskType}`);
                logToAsyncStorage(`[onForeground] Running Task: ${currentTaskType}`);
                await onLocation(location);
                scheduleNotification();
                currentTaskType = 'onLocation';
            });

            BackgroundGeolocation.onLocation(async location => {
                if (currentTaskType === 'onLocation') {
                    const now = Date.now();

                    // Throttle updates to every 3 seconds
                    if (now - lastLocationTimestamp < MIN_LOCATION_INTERVAL) {
                        logToAsyncStorage('Skipping location update to avoid excessive renders [onLocation]');
                        console.log('Skipping location update to avoid excessive renders [onLocation]');
                        return;
                    }

                    lastLocationTimestamp = now;
                    console.log(`[onForeground] Running Task: ${currentTaskType}`);
                    logToAsyncStorage(`[onForeground] Running Task: ${currentTaskType}`);
                    await onLocation(location);
                }
            }, onError);

            await BackgroundGeolocation.ready({
                locationAuthorizationRequest: 'Always',
                reset: true,
                desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
                debug: false,
                distanceFilter: 10,
                logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
                stopOnTerminate: false,
                startOnBoot: true,
                foregroundService: true,
                enableHeadless: true,
                notification: {
                    title: 'Tracking',
                    text: 'Location tracking is active',
                    color: '#FF0000',
                    priority: BackgroundGeolocation.NOTIFICATION_PRIORITY_LOW,
                },
                disableMotionActivityUpdates: false,
                disableAutoStop: true,
            });

            await BackgroundGeolocation.start();
            scheduleNotification();
        } catch (error) {
            console.error('Error configuring BackgroundGeolocation:', error);
        }
    };

    const emailLogs = async () => {
        try {
            await BackgroundGeolocation.logger.emailLog('libantech.net@gmail.com', {
                subject: 'Background Geolocation Logs',
                body: 'Please find the attached logs for debugging.',
            });
        } catch (error) {
            console.error('Error sending logs via email:', error);
        }
    };
    const onError = error => {
        console.error('tracking', 'Location error:', error);
    };

    const sendPointsToServer = async points => {
        try {
            const personString = await AsyncStorage.getItem('person');
            const person = JSON.parse(personString);

            if (!person || !person.fileNumber) {
                console.warn('[onForeground]Invalid person data [sendPointsToServer]:', person);
                return false;
            }

            const requestBody = await points.map(point => ({
                file_number: person.fileNumber,
                latitude: point.y.toString(),
                longitude: point.x.toString(),
                timestamp: point.timestamp,
            }));

            const response = await ApiMethod.postDataToServer(Api.locations, requestBody);
            // console.log('Sent points to server:', response?.success);
            return response?.success;
        } catch (error) {
            console.error('Failed to send points to server:', error);
            return false;
        }
    };

    const initializeWebSocket = () => {
        if (wsRef) {
            wsRef.close();
        }

        wsRef = new WebSocket(Api.SOCKET_URL);

        return new Promise(resolve => {
            wsRef.onopen = () => {
                isConnected = true;
                // console.log('tracking', 'WebSocket connection opened');
                ApiMethod.postDataToServer(Api.update_user_status, {
                    file_number: '1997',
                    status: 'active',
                });
                resolve();
            };

            wsRef.onclose = () => {
                isConnected = false;
                // console.log('tracking', 'WebSocket connection closed');
                // ApiMethod.postDataToServer(Api.update_user_status, {
                //     file_number: '1997',
                //     status: 'inactive',
                // });
            };

            wsRef.onerror = async () => {
                // console.log('onerror');
                // ApiMethod.postDataToServer(Api.update_user_status, {
                //     file_number: '1997',
                //     status: 'inactive',
                // });
                isConnected = false;
            };
        });
    };

    const onLocation = async location => {
        const state = await NetInfo.fetch();
        isConnected = state.isConnected;
        const tracking = (await AsyncStorage.getItem('tracking')) === 'true';

        if (!location || !location.coords) {
            console.error('tracking', 'Invalid location object:', location);
            return;
        }

        setLocation(location.coords);
        const point = {
            x: location.coords.longitude,
            y: location.coords.latitude,
            timestamp: new Date().toISOString(),
        };
        const storedPoints = await AsyncStorage.getItem('tracking_points');
        const pointsArray = storedPoints ? await JSON.parse(storedPoints) : [];

        // Add the new point
        await pointsArray.push(point);

        // Save the updated points array back to AsyncStorage
        await AsyncStorage.setItem('tracking_points', JSON.stringify(pointsArray));
        console.log('[onForeground]: Saved point locally:', pointsArray.length);
        logToAsyncStorage(`[onForeground]: Saved point locally:, ${pointsArray.length}`);

        if (isConnected && tracking) {
            await sendLocation(location);
        } else {
            if (wsRef) {
                await wsRef.close();
                wsRef = null;
            }
        }
    };

    const sendLocation = async location => {
        if (!wsRef || wsRef.readyState !== WebSocket.OPEN) {
            try {
                await initializeWebSocket();
            } catch (error) {
                console.error('tracking', 'Failed to establish WebSocket connection', error);
                return;
            }
        }

        if (wsRef && wsRef.readyState === WebSocket.OPEN) {
            try {
                let personString = await AsyncStorage.getItem('person');
                const person = await JSON.parse(personString);

                if (!person || !person.id) {
                    console.warn('Invalid person data:', person);
                    return;
                }

                const message = {
                    x: location.coords.longitude,
                    y: location.coords.latitude,
                    fileNumber: person.fileNumber,
                    name: person.name,
                    id: person.id,
                };
                logToAsyncStorage(
                    'tracking' +
                        'Sent message:' +
                        'x:' +
                        message.x +
                        'y:' +
                        message.y +
                        moment(location.timestamp).format('YYYY-MM-DD HH:mm:ss')
                );
                wsRef.send(JSON.stringify(message));
                console.log(
                    '[onForeground]',
                    'Sent message:',
                    message,
                    moment(location.timestamp).format('YYYY-MM-DD HH:mm:ss')
                );
            } catch (error) {
                console.error('Failed to parse person data or send location:', error);
            }
        }
    };

    async function logToAsyncStorage(message) {
        const logMessage = `[${new Date().toISOString()}] ${message}\n`;
        let currentLogs = await AsyncStorage.getItem('appLogs');
        currentLogs = currentLogs ? currentLogs : '';
        await AsyncStorage.setItem('appLogs', currentLogs + logMessage);
    }
    async function getLogs() {
        const logs = await AsyncStorage.getItem('appLogs');
        console.log('Stored Logs:', logs);
    }

    return (
        <TrackingContext.Provider value={{ StopTracking, StartTracking, location, emailLogs }}>
            {children}
        </TrackingContext.Provider>
    );
};

export default TrackingComponent;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//this code is for run code in headless 

import { AppRegistry, DeviceEventEmitter } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
import BackgroundGeolocation from 'react-native-background-geolocation';
import AsyncStorage from '@react-native-async-storage/async-storage';
import moment from 'moment';
import interceptor from './src/services/interceptor';
import Api from './src/util/api';
import NetInfo from '@react-native-community/netinfo';
import WorkManager from './src/component/WorkManager';
import messaging from '@react-native-firebase/messaging';

AppRegistry.registerComponent(appName, () => App);
interceptor.setupInterceptors();

messaging().setBackgroundMessageHandler(async remoteMessage => {
    const tracking = (await AsyncStorage.getItem('tracking')) === 'true';
    if (!tracking) {
        return;
    }

    await BackgroundGeolocation.getState(async state => {
        if (state.enabled) {
            console.log(remoteMessage);
            configureBackgroundGeolocation();
        }
    });
});

let wsRef = null;
let isConnected = null;
let currentTaskType = 'onLocation';
let eventListenerSubscription = null;
let lastLocationTimestamp = 0;
const MIN_LOCATION_INTERVAL = 3000; // Minimum interval (3 seconds) between location updates

const configureBackgroundGeolocation = async () => {
    try {
        // Ensure previous listeners are removed
        await BackgroundGeolocation.removeListeners();
        await BackgroundGeolocation.removeAllListeners();
        await BackgroundGeolocation.stop();
        await WorkManager.CancelWork();
        if (eventListenerSubscription) {
            await eventListenerSubscription.remove();
            DeviceEventEmitter.removeAllListeners('livelocationapp');
            console.log('Event listener removed');
        }

        await BackgroundGeolocation.ready({
            locationAuthorizationRequest: 'Always',
            reset: true,
            desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
            debug: false,
            distanceFilter: 10,
            logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
            stopOnTerminate: false,
            startOnBoot: true,
            foregroundService: true,
            enableHeadless: true,
            notification: {
                title: 'Tracking',
                text: 'Location tracking is active',
                color: '#FF0000',
                priority: BackgroundGeolocation.NOTIFICATION_PRIORITY_LOW,
            },
            disableMotionActivityUpdates: false,
            disableAutoStop: true,
        });

        await BackgroundGeolocation.start();
        scheduleNotification();
    } catch (error) {
        console.error('Error configuring BackgroundGeolocation:', error);
    }
};

async function logToAsyncStorage(message) {
    const logMessage = `[${new Date().toISOString()}] ${message}\n`;
    let currentLogs = await AsyncStorage.getItem('appLogs');
    currentLogs = currentLogs ? currentLogs : '';
    await AsyncStorage.setItem('appLogs', currentLogs + logMessage);
}
// Initialize WebSocket
const initializeWebSocket = () => {
    if (wsRef && wsRef.readyState === WebSocket.OPEN) {
        return Promise.resolve();
    }

    return new Promise((resolve, reject) => {
        wsRef = new WebSocket(Api.SOCKET_URL);

        wsRef.onopen = () => {
            // console.log('Headless: WebSocket connection opened');
            resolve();
        };

        wsRef.onclose = () => {
            // console.log('Headless: WebSocket connection closed');
            wsRef = null;
            isConnected = null;
            reject(new Error('WebSocket connection closed'));
        };

        wsRef.onerror = error => {
            wsRef = null;
            isConnected = null;
            reject(error);
        };
    });
};

const sendLocation = async location => {
    let personString = await AsyncStorage.getItem('person');
    const person = await JSON.parse(personString);
    const tracking = (await AsyncStorage.getItem('tracking')) === 'true';

    if (!person || !tracking) {
        // console.log('Headless: File number not found or tracking is disabled');
        return;
    }

    try {
        await initializeWebSocket();

        if (wsRef && wsRef.readyState === WebSocket.OPEN) {
            const message = {
                x: location.coords.longitude,
                y: location.coords.latitude,
                fileNumber: person.fileNumber,
                name: person.name,
                id: person.id,
            };

            wsRef.send(JSON.stringify(message));

            logToAsyncStorage(
                'Headless: Sent message: ' +
                    ' x:' +
                    message.x +
                    ' y:' +
                    '  ' +
                    message.y +
                    '  ' +
                    moment(location.timestamp).format('YYYY-MM-DD HH:mm:ss')
            );
            console.log('Headless: Sent message:', message, moment(location.timestamp).format('YYYY-MM-DD HH:mm:ss'));
        }
    } catch (error) {
        console.error('Failed to send location:', error);
    }
};

const scheduleNotification = async () => {
    const tracking = (await AsyncStorage.getItem('tracking')) === 'true';
    if (!tracking) {
        return;
    }

    const interval = 10;
    WorkManager.schedulePeriodicWork(interval);
};

const BroadcastReceiver = async () => {
    const tracking = (await AsyncStorage.getItem('tracking')) === 'true';
    if (!tracking) {
        return;
    }
    if (eventListenerSubscription) {
        await eventListenerSubscription.remove();
        DeviceEventEmitter.removeAllListeners('livelocationapp');
        console.log('Event listener removed');
    }
    eventListenerSubscription = DeviceEventEmitter.addListener('livelocationapp', async () => {
        const now = Date.now();

        // Throttle updates to every 3 seconds
        if (now - lastLocationTimestamp < MIN_LOCATION_INTERVAL) {
            console.log('Skipping location update to avoid excessive renders');
            return;
        }
        lastLocationTimestamp = now;

        currentTaskType = 'onHeartbeat';

        const tracking = (await AsyncStorage.getItem('tracking')) === 'true';

        const location = await BackgroundGeolocation.getCurrentPosition({
            timeout: 30, // 30 second timeout to fetch location
            maximumAge: 500, // Accept the last-known-location if not older than 1 second.
            desiredAccuracy: 5, // Try to fetch a location with an accuracy of `10` meters.
            samples: 5, // How many location samples to attempt.
        });
        const point = {
            x: location.coords.longitude,
            y: location.coords.latitude,
            timestamp: new Date().toISOString(),
        };

        // Retrieve existing points from AsyncStorage
        const storedPoints = await AsyncStorage.getItem('tracking_points');
        const pointsArray = storedPoints ? JSON.parse(storedPoints) : [];

        // Add the new point
        pointsArray.push(point);

        // Save the updated points array back to AsyncStorage
        await AsyncStorage.setItem('tracking_points', JSON.stringify(pointsArray));
        console.log('[Headless]: Saved point locally[onHeartbeat]:', pointsArray.length);

        logToAsyncStorage('[Headless]: Saved point locally [onHeartbeat]:' + pointsArray.length);

        if (isConnected && tracking) {
            await sendLocation(location);
        } else {
            if (wsRef) {
                await wsRef.close();
                wsRef = null;
            }
        }
        scheduleNotification();
        currentTaskType = 'onLocation';
    });
};

const StartHeadlessTask = async () => {
    const tracking = (await AsyncStorage.getItem('tracking')) === 'true';
    if (!tracking) {
        return;
    }
    BackgroundGeolocation.registerHeadlessTask(HeadlessTask);
};
// Headless Task
const HeadlessTask = async event => {
    const tracking = (await AsyncStorage.getItem('tracking')) === 'true';

    if (!tracking) {
        await BackgroundGeolocation.removeListeners();
        await BackgroundGeolocation.stop();
        if (wsRef) {
            await wsRef.close();
            wsRef = null;
        }
        return;
    }

    const state = await NetInfo.fetch();
    isConnected = state.isConnected;

    switch (event.name) {
        case 'location': {
            if (currentTaskType === 'onLocation') {
                try {
                    const now = Date.now();

                    // Throttle updates to every 30 seconds
                    if (now - lastLocationTimestamp < MIN_LOCATION_INTERVAL) {
                        console.log('Skipping location update to avoid excessive renders');
                        break;
                    }

                    const state = await NetInfo.fetch();
                    isConnected = state.isConnected;

                    const location = event.params;

                    const point = {
                        x: location.coords.longitude,
                        y: location.coords.latitude,
                        timestamp: new Date().toISOString(),
                    };

                    // Retrieve existing points from AsyncStorage
                    const storedPoints = await AsyncStorage.getItem('tracking_points');
                    const pointsArray = storedPoints ? JSON.parse(storedPoints) : [];

                    // Add the new point
                    pointsArray.push(point);

                    // Save the updated points array back to AsyncStorage
                    await AsyncStorage.setItem('tracking_points', JSON.stringify(pointsArray));
                    console.log('[Headless]: Saved point locally[location]:', pointsArray.length);
                    logToAsyncStorage('[Headless]: Saved point locally [location]:' + pointsArray.length);
                    lastLocationTimestamp = now;
                    if (isConnected && tracking) {
                        await sendLocation(location);
                    } else {
                        if (wsRef) {
                            await wsRef.close();
                            wsRef = null;
                        }
                    }
                    // scheduleNotification();
                } catch (error) {
                    console.error('Error getting location on onLocation:', error);
                }
            }
            break;
        }
    }
};

// Register the Headless Task
scheduleNotification();
BroadcastReceiver();
StartHeadlessTask();

/////////////////////////////////////////////////////////////////////////////////////////

Steps to Reproduce

1. 2. 3. 4.

Context

Debug logs

Logs ``` PASTE_YOUR_LOGS_HERE [background-geolocation.log](https://github.com/user-attachments/files/16827730/background-geolocation.log) ```
christocracy commented 2 months ago

debug: false,

If you’re having a problem., the first thing you do is set that to true. See wiki “Debugging” here. Read the api docs Config.debug to learn what the debug sound-effects mean.

every time he send location get me notification 'location tracking is active ' this notification appear for a few seconds and hide quickly

That’s exactly what’s supposed to happen. Now go outside for a nice walk with a real device, moving at least 200 meters. You will likely hear more debug sound-effects and find the plug-in automatically start tracking.

read the wiki “Philosophy of Operation”,

jabal3amel commented 2 months ago

i set debug to true but the log does not get any problem I noticed that as long as the notifications are visible the app works fine, but when the notifications disappear the app stops working How can I show notifications to the user all the time Tracking

background-geolocation.log

christocracy commented 2 months ago

Your logs span a period of only ~20 minutes.

09-03 11:12:34.776 DEBUG [LoggerFacade$a a] ℹ️   Persist config, dirty: []
.
.
.
09-03 11:34:22.060 DEBUG [TerminateEvent$a onChange] 

Are you aware that this plugin strongly desires to be in the stationary-state, with location-services (and the corresponding foreground-service notification) OFF?

You are free to configure the stopTimeout to suit your needs. Your logs show its set to its default of 5 minutes ( "stopTimeout": 5). See API docs Config.stopTimeout

github-actions[bot] commented 1 month ago

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

github-actions[bot] commented 1 month ago

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