react-native-background-geolocation
react-native-background-geolocation copied to clipboard
[Help Wanted]: Inaccurate paths from coords.
Required Reading
- [x] Confirmed
Plugin Version
"react-native-background-fetch": "^4.2.8", "react-native-background-geolocation": "^4.18.6",
Mobile operating-system(s)
- [x] iOS
- [x] Android
Device Manufacturer(s) and Model(s)
iPhone 14, Samsung S Series
Device operating-systems(s)
iOS 17, Android 14/15
React Native / Expo version
RN - 0.74.5, Expo - 50
What do you require assistance about?
First of all, thanks for your hard work to maintain this amazing plugin. We recently have purchased the license to use this module in our app.
Our Use Case We want to track user's path when they are in a shift and calculate mileage from the path. We are relying on the coords from this module and drawing polylines to show the path on the map.
Issue I have done several test drives to check the paths. Most of the cases it works fine but we also frequently see weird paths. For example, check out the following image.
As in the image sometimes the poly lines just cuts straight through map (doesn't follow the street)
Some other examples of wrong paths from the coordinates,
Question
- Why is this happening? Is it due to GPS / Device issues or something on our end?
- Do I need to change some configs? We are mostly concerned to track users' path when they are driving to calculate mileage.
[Optional] Plugin Code and/or Config
// Relevant code
// MAIN setup and tracking
useEffect(() => {
let locationSubscription: any;
BackgroundGeolocation.ready({
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
distanceFilter: 20,
stopOnTerminate: true,
locationAuthorizationRequest: 'Always',
locationAuthorizationAlert: {
titleWhenNotEnabled: 'Location Services Required',
titleWhenOff: 'Location Services Required',
instructions:
"To calculate your trip mileage automatically, we need access to your location — even when the app is in the background.\n\nWe only use your location while you are on a trip. You'll always have full control, and your data stays private",
cancelButton: 'Cancel',
settingsButton: 'Settings',
},
backgroundPermissionRationale: {
title: 'Location Services Required',
message:
"To calculate your trip mileage automatically, we need access to your location — even when the app is in the background.\n\nWe only use your location while you are on a trip. You'll always have full control, and your data stays private",
positiveAction: 'Change to Allow all the time',
},
}).then(() => {
setIsBackgroundLocationEnabled(true);
// Location listener
locationSubscription = BackgroundGeolocation.onLocation(loc => {
if (loc.coords.accuracy && loc.coords.accuracy > 50) {
return;
}
if (loc.coords?.latitude && loc.coords?.longitude) {
const coords = {
latitude: loc.coords.latitude,
longitude: loc.coords.longitude,
timestamp: loc.timestamp,
accuracy: loc.coords.accuracy,
};
setTrackedCoords(prev => {
if (prev.length === 0 || prev[prev.length - 1].length === 0) {
const newCoords = [...prev, [coords]];
if (shiftId) {
storage.set(
`trip_coords_${shiftId}`,
JSON.stringify(newCoords),
);
}
return newCoords;
}
const newCoords = [...prev];
const currentSegment = newCoords[newCoords.length - 1];
newCoords[newCoords.length - 1] = [...currentSegment, coords];
if (shiftId) {
storage.set(`trip_coords_${shiftId}`, JSON.stringify(newCoords));
}
return newCoords;
});
}
});
});
return () => {
locationSubscription?.remove();
};
}, [shiftId, isTracking, isPaused]);
// Start, pause, resume, stop functions
const handleStartTrip = useCallback(
async (shouldClearCoords = true) => {
if (!isBackgroundLocationEnabled) {
Alert.alert(
'Location Services Required',
'Please enable location services in the settings to start tracking.',
);
return;
}
try {
await BackgroundGeolocation.start();
setIsTracking(true);
setIsPaused(false);
// Only clear coordinates if explicitly starting a new trip
if (shouldClearCoords) {
setTrackedCoords([]);
if (shiftId) {
storage.delete(`trip_coords_${shiftId}`);
}
setCalculatedDistance(0);
}
} catch (error) {
console.error('Error starting trip:', error);
}
},
[shiftId, isBackgroundLocationEnabled],
);
const handlePauseTrip = async () => {
try {
await BackgroundGeolocation.stop();
setIsPaused(true);
} catch (error) {
console.error('Error pausing trip:', error);
}
};
const handleResumeTrip = async () => {
if (!isBackgroundLocationEnabled) {
Alert.alert(
'Location Services Required',
'Please enable location services in the settings to resume tracking.',
);
return;
}
try {
await BackgroundGeolocation.stop();
// Add a new empty segment to the coordinates array
setTrackedCoords(prev => {
const newCoords = [...prev, []];
return newCoords;
});
// Start fresh tracking
await BackgroundGeolocation.start();
setIsPaused(false);
} catch (error) {
console.error('Error resuming trip:', error);
}
};
const handleStopTrip = async () => {
try {
await BackgroundGeolocation.stop();
setIsTracking(false);
setIsPaused(false);
// Only update parent component when trip stops
onDistanceUpdate(calculatedDistance);
if (shiftId) {
storage.set(
`trip_tracking_state_${shiftId}`,
JSON.stringify({
isTracking: false,
isPaused: false,
}),
);
}
} catch (error) {
console.error('Error stopping trip:', error);
}
};
// MAP VIEW
<MapView
ref={mapRef}
style={styles.map}
initialRegion={region}
showsUserLocation={isActiveTracking}
showsMyLocationButton={true}
followsUserLocation={isActiveTracking}>
{coordinates.map((segment, segmentIndex) => {
// Only render polyline if segment has at least 2 points
if (segment.length < 2) {
return null;
}
const startPoint = segment[0];
const endPoint = segment[segment.length - 1];
return (
<React.Fragment key={`segment-${segmentIndex}`}>
{/* Polyline for the route */}
<Polyline
coordinates={segment}
strokeColor={colors.primary[500]}
strokeWidth={4}
/>
{/* Start marker */}
<Marker
flat={true}
pinColor={colors.primary[500]}
coordinate={startPoint}
/>
{/* End marker */}
<Marker
flat={true}
pinColor={colors.primary[500]}
coordinate={endPoint}
/>
</React.Fragment>
);
})}
</MapView>
[Optional] Relevant log output
There’s a wide discrepancy of performance between different Android models.
See https://dontkillmyapp.com
Thank you for your response. Yes, I have seen the link from other issues as well in the repo.
Keeping this limitation in mind, can you please have a quick glance at the relevant code that I posted and if possible suggest us better ways to track? We believe we can play with some config props to make the tracking better. We are just concerned to track our users for the following,
- They are driving.
- The app is foreground & background.
- No need to track if the app is terminated.
Thank you again! 🙏
There is nothing unusual about your Config.
This issue is stale because it has been open for 30 days with no activity.
This issue was closed because it has been inactive for 14 days since being marked as stale.