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.62k stars 428 forks source link

Unable to fetch location in background on regular interval #2131

Open nipundixit2016 opened 2 weeks ago

nipundixit2016 commented 2 weeks ago

Your Environment

BackgroundGeolocation.ready({
      desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
      distanceFilter: 0, // Adjust the distance filter as necessary
      stopOnTerminate: false,
      startOnBoot: true,
      debug: true, // <-- Enable for debug purposes
      logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
      locationUpdateInterval: 120000, // 2 minutes
      fastestLocationUpdateInterval: 120000, // Minimum time between updates
      // heartbeatInterval: 60,
      allowIdenticalLocations: false,
      locationAuthorizationRequest: 'Always',
    })
//BackgroundGeolocation.ts

import BackgroundGeolocation from 'react-native-background-geolocation';
import axios from 'axios';
import Geocoder from 'react-native-geocoding';
import {BASE_URL, GOOGLE_MAPS_API_KEY} from './urls';
import {getFromLocalStorage, saveToLocalStorage} from './helpers';

Geocoder.init(GOOGLE_MAPS_API_KEY);

const fetchLocationAndSend = async location => {
console.log('Fetching location...');
const salesEmployeeCode = await getFromLocalStorage('SalesEmployeeCode');

try {
const {latitude, longitude} = location.coords;
console.log(location, 'location');
let positionsArray = [];

positionsArray = await getFromLocalStorage('positionsArray');
if (positionsArray.length > 0) {
  positionsArray = JSON.parse(positionsArray); // Parse the stored JSON string
}

// Add the new position to the array
const geocodeResponse = await Geocoder.from(latitude, longitude);
const address = geocodeResponse.results[0].formatted_address;
const currentDate = new Date();
const date = currentDate.toISOString().split('T')[0];
const time = currentDate.toLocaleTimeString();

const newPosition = {
  SalesEmployeeCode: salesEmployeeCode,
  Latitude: latitude.toString(),
  Longitude: longitude.toString(),
  Address: address,
  Create_Date: date,
  Create_Time: time,
};
positionsArray.push(newPosition);
console.log('bhupendra', positionsArray.length);

// Save the updated array back to local storage
await saveToLocalStorage('positionsArray', JSON.stringify(positionsArray));

console.log('Position saved to local storage:', newPosition);
} catch (error) {
console.error('Error in fetchLocationAndSend:', error);
}
};

const BackgroundTask = async taskId => {
console.log('[BackgroundTask] start');

try {
// Initialize BackgroundGeolocation
BackgroundGeolocation.ready({
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
distanceFilter: 0, // Adjust the distance filter as necessary
stopOnTerminate: false,
startOnBoot: true,
debug: true, // <-- Enable for debug purposes
logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
locationUpdateInterval: 120000, // 2 minutes
fastestLocationUpdateInterval: 120000, // Minimum time between updates
})
.then(state => {
console.log('- BackgroundGeolocation is ready: ', state);

    if (!state.enabled) {
      // BackgroundGeolocation.start(); // Start tracking if not already started
    }

    // Listen to location updates
    BackgroundGeolocation.onLocation(fetchLocationAndSend, error => {
      console.error('[onLocation] ERROR:', error);
    });
  })
  .catch(error => {
    console.warn('- BackgroundGeolocation error: ', error);
  });
} catch (error) {
console.error('Error in background task:', error);
}
};

export default BackgroundTask;

Expected Behavior

Return location each 2min while app is foreground , background or killed state

Actual Behavior

only getting once when BackgroundGeoLoaction.start()

Steps to Reproduce

1. 2. 3. 4.

Context

Debug logs

Logs
christocracy commented 2 weeks ago

When you post a block of code, you MUST syntax highlight it. I’ve told you this at least 4 times. It is not hard. You surround your code in triple-backticks (+optional language):

IMG_2114

nipundixit2016 commented 2 weeks ago

i have updated

christocracy commented 2 weeks ago
  1. When you register event-listeners (such as .onLocation), you do so BEFORE calling .ready(config), not within the Promise resolution.
// Register listeners HERE <-------------------------
BackgroundGeolocation.onLocation((location) => {
  console.log('[onLocation]', location);
});

BackgroundGeolocation.ready(config).then((state) => {
  // DO NOT REGISTER EVENT-LISTENERS HERE.

});
  1. Learn how this plugin operates by carefully reading the Wiki "Philosophy of Operation"

This plugin does not track location while the device is sitting stationary on your desk. The plugin tracks location ONLY when the device is detected to be moving (typically requires movement of at least 200 meters).

Go outside for a nice long walk of at least 1km. With debug: true, the plugin will emit debugging sound-effects to let you it's working. To leran what these debugging sound-effects mean, read the API docs Config.debug. The searchable API docs are conveniently linked in the README in the Table of Contents

Screenshot 2024-08-31 at 4 43 36 PM (1)
christocracy commented 2 weeks ago

About "wiring up event-listeners", the Example in the README clearly states the process. You need to stop "throwing crap at the wall" and carefully read and understand how this plugin works.

Screenshot 2024-08-31 at 4 47 50 PM (1)
christocracy commented 2 weeks ago

If you want periodic location updates (eg: about every 15 minutes) , you can do so by calling .getCurrentPosition in your BackgroundFetch callback.

  BackgroundFetch.configure({
      minimumFetchInterval: 15,  // <-- every 15 minutes is the fastest you'll get.
      enableHeadless: true,
      stopOnTerminate: false
    }, async (taskId) => {
      console.log('[BackgroundFetch]', taskId);
      const location = await BackgroundGeolocation.getCurrentPosition({
        samples: 3 // record 3 locations and return the most accurate of the three
      });
      console.log('[getCurrentPosition]', location);
      BackgroundFetch.finish(taskId);
    }, async (taskId) => {
      console.log('[BackgroundFetch] TIMEOUT:', taskId);
      BackgroundFetch.finish(taskId);
    });
nipundixit2016 commented 2 weeks ago

By periodic time everything working properly but when creating release build. it not working in that build.

christocracy commented 2 weeks ago

await saveToLocalStorage('positionsArray', JSON.stringify(positionsArray));

You don't need to store locations in localStorage. This plugin has its own built-in SQLite database.

Those recorded locations can be retrieved via .getLocations() and the database cleared via .destroyLocations().

The plugin also hosts its own built-in HTTP service. See API docs HTTP Guide for more information on all the plugin's HTTP Features.

christocracy commented 2 weeks ago

By periodic time everything working properly but when creating release build. it not working in that build.

You were not using BackgroundGeolocation before — you were using some other plugin named Geolocation.

If you have a problem, see Wiki Debugging and learn how to fetch the plugin's logs via .emailLog

nipundixit2016 commented 2 weeks ago

I am replacing Geolocation by BackgroundGeolocation hoping it works in release build.

christocracy commented 2 weeks ago

I am replacing Geolocation by BackgroundGeolocation hoping it works in release build.

Do not "hope" -- test it yourself with a local realease build on your own device FIRST.

With your device plugged into USB:

$ npx react-native run-android --mode=release
christocracy commented 2 weeks ago

and when running locally, ALWAYS observe $ adb logcat *:S TSLocationManager:V in a terminal window to view realtime logs from the plugin.

This plugin's logging system is incredibly verbose and prints absolutely everything that it's doing:

Screenshot 2024-08-31 at 5 09 24 PM
christocracy commented 2 weeks ago

If you don't know how to use adb logcat, learn how to

christocracy commented 2 weeks ago

And of course you probably didn't read how to simulate Android background-fetch tasks in a terminal window with adb shell

$ adb shell cmd jobscheduler run -f <your.application.id> 999
nipundixit2016 commented 2 weeks ago

'''

import React, { useEffect } from 'react'; import { AppRegistry, Platform, Alert } from 'react-native'; import App from './App'; import { name as appName } from './app.json'; import BackgroundGeolocation from 'react-native-background-geolocation';

const MainApp = () => { useEffect(() => { // Define a callback for location updates const onLocation = (location) => { console.log('[onLocation] -', location); // Handle location update };

// Define a callback for errors
const onError = (error) => {
  console.warn('[onError] -', error);
  // Handle error
};

// Define a callback for the state change
const onStateChange = (state) => {
  console.log('[onStateChange] -', state);
  // Handle state changes
};

// Define a callback for geofence events
const onGeofence = (geofence) => {
  console.log('[onGeofence] -', geofence);
  // Handle geofence events
};

// Set up event listeners
BackgroundGeolocation.onLocation(onLocation, onError);
// BackgroundGeolocation.onError(onError);
// BackgroundGeolocation.onStateChange(onStateChange);
BackgroundGeolocation.onGeofence(onGeofence);

// Configure BackgroundGeolocation
BackgroundGeolocation.ready({
  desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
  distanceFilter: 10, // Minimum distance (in meters) before update
  stopOnTerminate: false, // Continue tracking when the app is terminated
  startOnBoot: true, // Start tracking on device boot
  enableHeadless: true, // Enable headless mode for background tasks
  locationUpdateInterval: 60000, // Update interval in milliseconds
  notificationTitle: "Background Tracking",
  notificationText: "Enabled",
}).then((state) => {
  if (!state.enabled) {
    // Start tracking if not already enabled
    BackgroundGeolocation.start();
  }
}).catch((error) => {
  console.error('Error configuring BackgroundGeolocation:', error);
});

return () => {
  // Clean up listeners on unmount
  BackgroundGeolocation.removeListeners();
};

}, []);

return ; };

AppRegistry.registerComponent(appName, () => MainApp);

'''

christocracy commented 2 weeks ago

The [`] backtick character is not the [‘] single-quote.

https://superuser.com/questions/254076/how-do-i-type-the-tick-and-backtick-characters-on-windows

christocracy commented 2 weeks ago

I suggest you Google how to find the [`] backtick character for your keyboard.