I am working on a Sencha Touch (2.3.1) application, packaged using Cordova 3.5.0-0.2.7. I am trying to read GPS coordinates using:
navigator.geolocation.getCurrentPosition()
But the request is always timing out on Android Phones, while it is working fine in Chrome emulator. I have tried using watchPosition() also.
Any help would be much appreciated.
If you've not already, install cordova-plugin-geolocation into your project - i.e. cordova plugin add cordova-plugin-geolocation
- this will add the appropriate permissions to your Android manifest, as Mike Dailor rightly points out that you need.
What options are you passing as the third parameter to getCurrentPosition()
? The geolocationOptions object has 3 properties: timeout, maxAge and enableHighAccuracy.
Assuming you want an accurate position (i.e. GPS tracking/sat-nav type of app), setting enableHighAccuracy: true
causes your app to ask the OS retreive a position using the GPS hardware. In this case, you want to set a timeout value which allows enough time for the GPS hardware to obtain a fix for the first time, otherwise the timeout will occur before it has a chance to get a fix.
Also bear in mind the that the effect of turning off GPS on an Android device (e.g. changing setting Location Mode to "Battery Saving") varies depending on the Android version: either the OS is never able to retreive a high-accuracy position, so the TIMEOUT error occurs (PERMISSION_DENIED will not be received on Android) or a low accuracy position will be retrieved and passed instead using Wifi/cell triangulation.
I'd suggest using watchPosition() instead of getCurrentPosition() to retrieve the location; getCurrentPosition() makes a single request for the device position at that current point in time, so the position timeout may occur before the GPS hardware on the device has had a chance to get a position fix, whereas using watchPosition() you can setup a watcher which will call the success function each time the OS receives a location update from the GPS hardware. If you only want a single location, clear the watcher after receiving a position of sufficient accuracy. If GPS is turned off on the Android device when the watcher is added, it will continue to return a TIMEOUT error; my workaround for this is to clear and re-add the watcher after a number of consequetive errors.
So something along these lines:
var MAX_POSITION_ERRORS_BEFORE_RESET = 3,
MIN_ACCURACY_IN_METRES = 20,
positionWatchId = null,
watchpositionErrorCount = 0,
options = {
maximumAge: 60000,
timeout: 15000,
enableHighAccuracy: true
};
function addWatch(){
positionWatchId = navigator.geolocation.watchPosition(onWatchPositionSuccess, onWatchPositionError, options);
}
function clearWatch(){
navigator.geolocation.clearWatch(positionWatchId);
}
function onWatchPositionSuccess(position) {
watchpositionErrorCount = 0;
// Reject if accuracy is not sufficient
if(position.coords.accuracy > MIN_ACCURACY_IN_METRES){
return;
}
// If only single position is required, clear watcher
clearWatch();
// Do something with position
var lat = position.coords.latitude,
lon = position.coords.longitude;
}
function onWatchPositionError(err) {
watchpositionErrorCount++;
if (err.code == 3 // TIMEOUT
&& watchpositionErrorCount >= MAX_POSITION_ERRORS_BEFORE_RESET) {
clearWatch();
addWatch();
watchpositionErrorCount = 0;
}
}
addWatch();