Usual approach
As you can see from ngCordova documentation found here, the use of getCurrentPosition is most likely the easier way of getting current location. It looks like if the enableHighAccuracy to true could increase the possibity of getting a reliable current location.
I was working on my first IONIC app where i wanted to get the current location during the absence of internet.I started testing by trying to get the current location while roaming around and once i had a WIFI connection i was trying to verify captured location.
Results were not consistence and have even tried changing argument values but none gave consistence results. When searching out a but it appears like the results are coming out of a cached GPS values. Below is an approach where by repeatedly using the watchPosition gave better results.
Using watchPosition instead of getCurrentPosition
As there is an accuracy returned from the GeoLocation API the plan is to keep retrying till the desired level of accuracy is obtained. This retry time and interval would need to be configuration so that that i can be controlled a bit.
I have written a factory service for now it has only getCurrentPosition. We can expand it later.
Step 1
Delegate the call to a private method which will attempt to get a reliable location and as its asynchronous, we need to return a promise back so that the calling code can monitor that.
Code
I have written a factory service for now it has only getCurrentPosition. We can expand it later.
Step 1
Delegate the call to a private method which will attempt to get a reliable location and as its asynchronous, we need to return a promise back so that the calling code can monitor that.
Code
return {
getCurrentLocation : function (options) {
var deferred = $q.defer();
callStart = new Date().getTime() / 1000;
_getLocationWrapper({callStart:callStart,
deferred:deferred,
othOptions:options,
attempt:1});
return deferred.promise;
}
};
The "options" that needs to be used for watchPosition are taken as input but are also passed over with "othOptions". Other parameters used are self contained within the service method.
Step 2
A wrapper method is created for handling first invocation of the service method
Code
function _getLocationWrapper(options) {
var locCB=function(){return _getLocation(options);};
if ( options.attempt == 1 ) {
locCB();
} else {
setTimeout(locCB, options.othOptions.gps.interval*1000);
}
}
Step 3
Calls the $cordovaGeolocation.watchPosition and in the callback of that
When error, return back the error too.
When success,
- Check for the desired accuracy and if achieved then return back same or callback the wrapper again.
- If timeout is reached but the desired accuracy is not obtained then feedback that as error.
In all the processing feedback to client on the progress/retries using deferred's "notify"
Code
function _getLocation(options){
var callStart = options.callStart;
var deferred = options.deferred;
var attempt = options.attempt;
var othOptions = options.othOptions;
deferred.notify({attempt: attempt, message:'Searching attempt '+attempt, lastAccuracy : options.lastAccuracy});
var getLocOptions = {
enableHighAccuracy: othOptions.gps.enableHighAccuracy,
timeout: othOptions.gps.timeout * 100,
maximumAge: 0
};
var locWatch = $cordovaGeolocation.watchPosition(getLocOptions);
locWatch.then(
null,
function(err) {
locWatch.clearWatch();
deferred.reject({err:err});
},
function(position) {
var callEnd = new Date().getTime() / 1000;
locWatch.clearWatch();
if ( position.coords.accuracy && position.coords.accuracy <= othOptions.gps.accuracy ) {
// This is good accuracy then accept it
deferred.resolve({status:0, position:position});
} else if ( (callEnd - callStart) < othOptions.gps.timeout ) {
// Keep trying till the configured wait time. If exceeds then return back.
options.attempt++;
options.lastAccuracy = Math.round(position.coords.accuracy * 100) / 100;
options.minAccuracy = options.minAccuracy || options.lastAccuracy; // Default
options.minAccuracy = options.minAccuracy < options.lastAccuracy ? options.lastAccuracy : options.minAccuracy;
_getLocationWrapper(options);
} else {
deferred.reject( {error:{code:-999, message:"Could not get location.<br>Minimum accuracy is "+options.minAccuracy+" mts.<br>Try to check location in open area or try adjusting to acceptable accuracy."}} );
}
}
);
}
Step 4
Finally client invocation
Code
var locationService = GSSearchLocationService.getCurrentLocation(
{
enableHighAccuracy : true,
timeout : 120, // In seconds
interval : 5, // Retry interval in seconds
accuracy : 15 // Accuracy distance in meters
}
);
locationService.then(
function(options) {
// put your success callback
},
function(options) {
// put your error callback
},
function(notificationData) {
// Put your retry notification messages
// Example showing a Ionic Loading message
// $ionicLoading.show({
// template: 'Getting Current Position...'
// + '<br>Attempts : '+notificationData.attempt+' <br>Accurracy(m) : '
// + notificationData.lastAccuracy
// });
}
);
Download
Full service code can be downloaded from here and kindly modify it accordingly.