react-native-background-geolocation
react-native-background-geolocation copied to clipboard
`getCurrentPosition` does not honor timeout and gets stuck when no connection is available
Your Environment
- Plugin version: tested on 4.8.0 and 4.8.2
- Platform: Android
- OS version: Android 12
- Device manufacturer / model: Oppo / PDEM30
- React Native version (
react-native -v): tested on both 0.64.2 and 0.68.2 - Plugin config
For our production app, we use this
{
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
reset: true,
stopTimeout: 1,
distanceFilter: 1000,
heartbeatInterval: 60,
debug: false,
logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
stopOnTerminate: true,
startOnBoot: false,
url: baseUrl + "/api/v1/position", // baseUrl is our hosted api but it also works when using the demo server
batchSync: true,
autoSync: false,
notification: {
title: "TrackPilot Go",
text: translate("LOCATION_SERVICE_ACTIVATED_MESSAGE"),
priority: BackgroundGeolocation.NOTIFICATION_PRIORITY_MAX,
},
}
The demo app uses
{
// Debug
reset: false,
debug: true,
logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
transistorAuthorizationToken: token,
// Geolocation
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_NAVIGATION,
distanceFilter: 10,
stopTimeout: 5,
// Permissions
locationAuthorizationRequest: 'Always',
backgroundPermissionRationale: {
title: "Allow {applicationName} to access this device's location even when closed or not in use.",
message: "This app collects location data to enable recording your trips to work and calculate distance-travelled.",
positiveAction: 'Change to "{backgroundPermissionOptionLabel}"',
negativeAction: 'Cancel'
},
// HTTP & Persistence
autoSync: true,
maxDaysToPersist: 14,
// Application
stopOnTerminate: false,
startOnBoot: true,
enableHeadless: true
}
Expected Behavior
The call to getCurrentPosition should throw or enter the error callback after the set timeout
Actual Behavior
It gets stuck forever. In rare cases, when a location can be obtained afterwards or when shaking the device, it continues with the success callback.
Steps to Reproduce
- Find a place with very bad GPS and WIFI
- In the demo app, trigger a
getCurrentPositioncall - Now comes a weird thing, I'm not sure if this is necessary but sometimes 2 would still find a location. If it does, quit the app and try again
The code is taken from the sample app, modified to try with callback and promises. Both yield the same results.
BackgroundGeolocation.getCurrentPosition({
persist: true,
samples: 1,
timeout: 30,
extras: {
getCurrentPosition: true
}
}, (location:Location) => {
console.log('[getCurrentPosition] success: ', location);
}, (error:LocationError) => {
console.warn('[getCurrentPosition] error: ', error);
});
BackgroundGeolocation.getCurrentPosition({
persist: true,
samples: 1,
timeout: 30,
extras: {
getCurrentPosition: true
}
}).then((location:Location) => {
console.log('[getCurrentPosition] success: ', location);
}).catch((error:LocationError) => {
console.warn('[getCurrentPosition] error: ', error);
});
Context
We are experiencing issues with getCurrentPosition when in places where a position cannot be determined, e.g. an insulated basement or a Faraday cage, for testing purposes. This does not happen when location is disabled globally in the device.
Debug logs
Since these are huge (3.5k lines long), I figured a paste would be better than the issue. You can find it here
modified to try with callback and promises
There is no functional difference between the two forms. If you use the old api and provide callback args, the plugin's Javascript api simply feeds your supplied callbacks into its internal Promise API. Ultimately, it's all Promise.
I will attempt to reproduce this.
As soon as we upgraded from 4.4.4 to 4.8.2 we started seeing this issue. We have critical part of our app where we block the user from pressing a continue button util we either get a Promise resolve or reject.
@curtisy1 says it does not honour the timeout.
I'll expand on that by saying it doesn't FULLY honour the time out. It seems like it stops trying to get a fix after X seconds but doesn't send the reject.
Testing with various timeouts
- Testing with 3 users in different locations on Android 10 & Android 12.
- Our devices get config from config server so I can change the timeout on the fly.
RESULTS Low Timeout Config (2 seconds)
- User 1 - NEVER worked, always hangs.
- User 2 - Only worked once, most just hangs.
- User 3 - Sometimes resolved with a GPS location but mostly failed. When it worked it seem to work a few times back to back.
RESULTS High Timeout Config (60 seconds)
- User 1 - WORKED, resolved after 6-12 seconds.
- User 2 - WORKED, resolved within 3-6 seconds.
- User 3 - WORKED, resolved within 5 seconds, sometimes less than 2 seconds.
Library Version 4.4.4
It always either retuned the GPS location within the timeout value or we got a promise reject when the timeout had expired, e.g. after 2 seconds.
Library Version 4.8.2 It either:
- Returns the GPS location within the timeout OR
- hangs and never returns a
resolveor areject
WORKAROUND?
Is there any suggested workaround for this that could safely abort the call after X seconds?
Note we did make 1 other change as the upgrade to 4.8.2 wouldn't work without it:
implementation ("androidx.appcompat:appcompat:1.3.1") {version {strictly '1.3.1'}}
we replicate the error on versions 4.8.1 and 4.8.2: timeout does not work. it is not possible to obtain neither "location" nor "locationerror"
BackgroundGeolocation.getCurrentPosition({
timeout: timeout, // n second timeout to fetch location
maximumAge: 30000, // Accept the last-known-location if not older than 30 sec.
desiredAccuracy: 10, // Try to fetch a location with an accuracy of `10` meters.
samples: 1, // How many location samples to attempt.
}, (location) => {
console.log('***** getCurrentPosition ok:' + JSON.stringify(location));
if (Url != null) {
UrlCorrente = Url;
setCRefresh(String(++count)); // serve a forzare un cambio di stato e di conseguenza un refresh della WebView
console.log("** count: " + count);
}
}, (locationerror) => {
console.log('***** getCurrentPosition error:' + JSON.stringify(locationerror));
if (Url != null) {
UrlCorrente = Url;
setCRefresh(String(++count)); // serve a forzare un cambio di stato e di conseguenza un refresh della WebView
console.log("** count: " + count);
}
});
Thanks! I can confirm release 4.9.3 fixes this bug (though I wonder how you reproduced it in the end :smile: )
wonder how you reproduced
By setting a low timeout, eg 0 or 1