I am creating a log file, and then saving the coordinates when app run in background through backgroundGeolocation. The problem is when app runs in background mode then it's not saving the coords in log file, actually I am doing this for testing purposes that does this plugin working fine or not.
document.addEventListener("deviceready",onDeviceReady,false);
// PhoneGap is ready to be used!
//
function onDeviceReady() {
window.logToFile.setLogfilePath('/myapp/log.txt', function () {
backgroundGeolocation.configure(callbackFn, failureFn, {
desiredAccuracy: 10,
stationaryRadius: 20,
distanceFilter: 30,
interval: 60000
});
backgroundGeolocation.start();
}, function (err) {
// logfile could not be written
// handle error
});
var callbackFn = function(location) {
window.logToFile.debug('[js] BackgroundGeolocation callback: ' + location.latitude + ',' + location.longitude);
backgroundGeolocation.finish();
};
var failureFn = function(error) {
console.log('BackgroundGeolocation error');
};
}
Related
I have the error like in question, when I'm trying to design my application to call native.camera, I see my console in ionic 3 project, I saw this error :
Native : tried calling Camera.getPicture, but Cordova is not available. Make sure to include cordova.js or run in a device / simulator.
Here is the code that I used to called native camera.
This is the code in my problem.html
<button class="logoCamera" ion-button (click)="presentActionSheet()">
<ion-icon name="camera" ></ion-icon>
This is the code in my problem.ts
import { File } from '#ionic-native/file';
import { Transfer, TransferObject} from '#ionic-native/transfer';
import { FilePath } from '#ionic-native/file-path';
import { Camera } from '#ionic-native/camera';
public presentActionSheet(){
let actionSheet = this.actionSheetCtrl.create({
title: 'Select Image',
buttons: [
{
text: 'Load from Library',
handler: () => {
this.takePicture(this.camera.PictureSourceType.PHOTOLIBRARY);
}
},
{
text: 'Use Camera',
handler: () => {
this.takePicture(this.camera.PictureSourceType.CAMERA);
}
},
{
text: 'Cancel',
role: 'cancel'
}
]
});
actionSheet.present();
}
public takePicture(sourceType){
//Create option for the Camera dialog
var options = {
quality: 100,
sourceType : sourceType,
saveToPhotoAlbum: false,
correctOrientation: true
};
//Get the data of an image
this.camera.getPicture(options).then((imagePath) => {
//special handling for android lib
if(this.platform.is('android') && sourceType === this.camera.PictureSourceType.PHOTOLIBRARY) {
this.filePath.resolveNativePath(imagePath)
.then(filePath => {
let correctPath = filePath.substr(0, filePath.lastIndexOf('/') + 1 );
let currentName = imagePath.substring(imagePath.lastIndexOf('/') + 1, imagePath.lastIndexOf('?'));
this.copyFileToLocalDir(correctPath, currentName, this.createFileName());
});
} else {
var currentName = imagePath.substr(imagePath.lastIndexOf('/') + 1);
var correctPath = imagePath.substr(0, imagePath.lastIndexOf('/')+ 1);
this.copyFileToLocalDir(correctPath, currentName, this.createFileName());
}
}, (err) => {
this.presentToast('Error while selecting Image.');
});
}
//Create a new name for image
private createFileName() {
var d = new Date(),
n = d.getTime(),
newFileName = n + ".jpg";
return newFileName;
}
//copy image to local folder
private copyFileToLocalDir(namePath, currentName, newFileName) {
this.file.copyFile(namePath, currentName, cordova.file.dataDirectory, newFileName).then(success => {
this.lastImage = newFileName;
}, error => {
this.presentToast('Error while storing file.');
});
}
private presentToast(text) {
let toast = this.toastCtrl.create({
message: text,
duration: 3000,
position: 'middle'
});
toast.present();
}
public pathForImage(img){
if (img === null) {
return '';
} else {
return cordova.file.dataDirectory + img;
}
}
public uploadImage() {
//destination URL
var url = "";
//file to upload
var targetPath = this.pathForImage(this.lastImage);
//file name only
var filename = this.lastImage;
var options = {
fileKey: "file",
fileName: filename,
chunkedMode: false,
mimeType: "multipart/form-data",
params: {'fileName': filename}
};
const fileTransfer: TransferObject = this.transfer.create();
this.loading = this.loadingCtrl.create({
content: 'Uploading...',
});
this.loading.present();
//use FileTransfer to upload image
fileTransfer.upload(targetPath, url, options).then(data => {
this.loading.dismissAll()
this.presentToast('Image successful uploaded.');
}, err => {
this.loading.dismissAll()
this.presentToast('Error while uploading file.');
});
}
When I run ionic serve, everything is smooth, no error, no nothing.
But when I click my button to access natve camera, the error shows, please help me figure out the problem, I check a lot of web, and none of it solve my question.
After I try run ionic cordova run ios --simulator, there are error coming out, but I am pretty sure that this error does not exist before I run this command.
May I know how to solve this problem ??
The error message is pretty accurate here:
Native : tried calling Camera.getPicture, but Cordova is not available. Make sure to include cordova.js or run in a device / simulator.
Running ionic serve does not include cordova.js nor does it run your application in a simulator or on a device which is why you get the error. You can fix it either by running your application on the device or simulator:
ionic cordova run android/ios --device/--simulator
Or by adding the browser platform:
cordova platform add browser
And running the browser platform:
ionic cordova run browser
I'm trying to get current geolocation in Ionic 2 to work on Android devices. In the browser it works well, but when I run the ionic cordova run android command to deploy on device the geolocation doesn't execute at all, and I get the following errors:
Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode. main.js:48746
Native: deviceready did not fire within 2000ms. This can happen when plugins are in an inconsistent state. Try removing plugins from plugins/ and reinstalling them. cordova.js:1223 (anonymous) # main.js:48746
deviceready has not fired after 5 seconds. main.js:48741
DEVICE READY FIRED AFTER 3656 ms main.js:119892
Ionic Native: deviceready event fired after 3519 ms main.js:122839
Ionic Storage driver: asyncStorage main.js:50230
navigator.geolocation works well main.js:8291
PlacesPage ionViewDidLoad error: this.getGeolocation is not a function
Mainly, what I don't understand is that I get the this.getGeolocation is not a function because how did that change from browser to device?
import { Geolocation } from '#ionic-native/geolocation';
...
constructor(private geolocation: Geolocation) {}
...
ionViewDidLoad() {
if(this.platform.is('cordova') === true){
document.addEventListener("deviceready", onDeviceReady, false);
}else{
console.log('Browser geolocation')
this.getGeolocation();
}
function onDeviceReady() {
console.log("navigator.geolocation works well");
this.getGeolocation();
}
}
getGeolocation(){
console.log('Starting Geolocation');
var options = {
enableHighAccuracy: true
};
this.geolocation.getCurrentPosition(options)
.then((position) => {
console.log('Geolocation successful');
this.currentLocation = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
let query = '?lat=' + position.coords.latitude + '&lng=' + position.coords.longitude;
this.updatePlaces(query);
}).catch((error) => {
console.log('Error getting location', error);
});
}
I have tried removing all plugins and reinstalling them. I have added a Content-Security-Policy to index.html.
Can anybody tell me what's wrong or guide me in a right direction? Thanks.
your code doesn't seems correct to me. Change your code to below:
import { Geolocation } from '#ionic-native/geolocation';
...
constructor(private geolocation: Geolocation) {}
...
ionViewDidLoad() {
if(this.platform.is('cordova') === true){
document.addEventListener("deviceready", onDeviceReady, false);
}else{
console.log('Browser geolocation')
this.getGeolocation();
}
}
function onDeviceReady() {
console.log("navigator.geolocation works well");
this.getGeolocation();
}
getGeolocation(){
console.log('Starting Geolocation');
var options = {
enableHighAccuracy: true
};
this.geolocation.getCurrentPosition(options)
.then((position) => {
console.log('Geolocation successful');
this.currentLocation = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
let query = '?lat=' + position.coords.latitude + '&lng=' + position.coords.longitude;
this.updatePlaces(query);
}).catch((error) => {
console.log('Error getting location', error);
});
}
I seem to have solved the issue. The problem was that I have been mixing the implementation of Cordova's geolocation and the implementation for Ionic. In Ionic it's not needed to add the event listener (I guess it handles that under the hood) as seen in the docs, so the proper implementation should be like this:
import { Geolocation } from '#ionic-native/geolocation';
...
constructor(private geolocation: Geolocation) {}
...
ionViewDidLoad() {
this.getGeolocation();
}
getGeolocation(){
console.log('Starting Geolocation');
var options = {
enableHighAccuracy: true
};
this.geolocation.getCurrentPosition(options)
.then((position) => {
console.log('Geolocation successful');
this.currentLocation = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
let query = '?lat=' + position.coords.latitude + '&lng=' + position.coords.longitude;
this.updatePlaces(query);
}).catch((error) => {
console.log('Error getting location', error);
});
}
I already had this code before I implemented the event listener, but at that time the plugins were failing, so it was an attempt to fix that, which got to implement the event listener. Thanks to #Prerak Tiwari for making me think in the right direction.
Usecase: Track associate location, as soon as he logs-in but closes the app later.
Using https://github.com/mauron85/cordova-plugin-background-geolocation plugin.
In debug mode, its showing the values, however, in the callback function, its not making the server calls.
renderMaps function calls navigator.geolocation.getCurrentPosition
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
// Now safe to use device APIs
renderMaps();
var callbackFn = function(location) {
var data = 'longitude='+ location.longitude + '&latitude=' + location.latitude + '&id=' + vm.user_id + '&token=' + vm.accessToken;
window.longitude_sel = location.latitude;
window.latitude_sel = location.longitude;
console.log("" + data);
$.ajax({
type: "POST",
url: "https://example.com/partner/location",
data: data,
success: function(response){
console.log("RESPONSE" + response);
}
});
backgroundGeolocation.finish();
};
var failureFn = function(error) {
console.log('BackgroundGeolocation error');
};
// BackgroundGeolocation is highly configurable. See platform specific configuration options
backgroundGeolocation.configure(callbackFn, failureFn, {
desiredAccuracy: 5,
stationaryRadius: 0,
distanceFilter: 30,
interval: 60000,
stopOnTerminate: false,
startOnBoot: false,
startForeground: true,
stopOnStillActivity: false,
debug: true
});
backgroundGeolocation.start();
console.log("TEST");
}
Try this solution. Its working in my case:
$$(document).on('deviceready', function() {
cordova.plugins.backgroundMode.enable();
alert('device working!');
var userId=localStorage.getItem("userId");
if(userId!=null)
{
BackgroundGeolocation.configure({
locationProvider: BackgroundGeolocation.ACTIVITY_PROVIDER,
desiredAccuracy: BackgroundGeolocation.HIGH_ACCURACY,
stationaryRadius: 50,
distanceFilter: 50,
notificationTitle: 'Background tracking',
notificationText: 'enabled',
debug: true,
interval: 10000,
fastestInterval: 5000,
activitiesInterval: 10000,
url: 'http://example.com/index.php/locations/savebackgroundlocation',
httpHeaders: {
"Authorization": "Basic " + btoa('stack' + ":" + 'pwd#123#')
},
// customize post properties
postTemplate: {
lat: '#latitude',
lon: '#longitude'
}
});
BackgroundGeolocation.checkStatus(function(status) {
BackgroundGeolocation.start(); //triggers start on start event
});
}
});
try using 'url' option of the plugin.
don't expect your callback to work every time, as your app activity might be killed in the background by the OS, which will also kill your callback.
besides this, service should survive the kill, so if you use url option of the plugin, you can still get your updates on the server
I had to give ACCESS_BACKGROUND_LOCATION permission
In the file plugins/cordova-plugin-geolocation/plugin.xml you need to add:
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
See more here: https://developer.android.com/training/location/background
I want to check the location and store the required data in the internal storage of the mobile. To stop this task, use has to tap stop button in the main ui. As this task started, no matter the state of the app, that task should do its work.
I can implement this using native android command. But I want to implement this using cordova and I can't figure out a way to do this..
If this task cannot be done using cordova, can I do it using native android and inject to the cordova app..??
Please help..
You can do this using the ng-cordova geolocation watcher, it watches geolocation properties such as lat, lon, and speed.
first intall ng-cordova and inject it
bower install ngCordova
angular.module('myApp', ['ngCordova'])
then install the geolocation plugin
cordova plugin add org.apache.cordova.geolocation
then you want to create a watcher, make sure to fire it after a device ready event or it will cause problems
This is what device ready function looks like
document.addEventListener("deviceready", function () {
$cordovaPlugin.someFunction().then(success, error);
}, false);
here is the watcher controller:
module.controller('GeoCtrl', function($cordovaGeolocation) {
var watchOptions = {
frequency : 1000,
timeout : 3000,
enableHighAccuracy: false // may cause errors if true
};
var watch = $cordovaGeolocation.watchPosition(watchOptions);
watch.then(
null,
function(err) {
// error
},
function(position) {
var lat = position.coords.latitude
var long = position.coords.longitude
});
watch.clearWatch();
// OR
$cordovaGeolocation.clearWatch(watch)
.then(function(result) {
// success
}, function (error) {
// error
});
});
As you watch their geolocation info you can push it into a local database like http://pouchdb.com/ or couch db or a server database. If you want to use this in any state of the app you can make it into a service,
here is an example in a app i built
service.watchSpeed = function () {
console.log('watcher');
ionic.Platform.ready(function () {
var watchOptions = {
frequency: 15 * 60 * 1000,
timeout: 1 * 60 * 1000,
enableHighAccuracy: true // may cause errors if true
};
service.watch = $cordovaGeolocation.watchPosition(watchOptions);
service.watch.then(
null,
function (err) {
service.watchSpeed();
},
function (position) {
if (service.maxspeed.ToUseApp !== 0) {
var lat = position.coords.latitude;
var long = position.coords.longitude;
var speed = position.coords.speed;
service.speed = speed;
if (speed > service.maxspeed.ToUseApp) {
$state.go('overspeed');
}
if ($ionicHistory.currentStateName() === 'overspeed' && speed < service.maxspeed.ToUseApp) {
$ionicHistory.goBack();
}
} else {
console.log('speed watcher has been killed, why master??');
}
});
});
};
then in my home controller i call the watcher
ionic.Platform.ready(function () {
ffService.getMaxSpeed();
});
I have created an ionic angularjs ngCordova mobile app, wherein I have used ngCorodova geolocation plugin in order to get user location. when I am testing this on browser it works fine. but when same I [android-app.apk] I install on mobile app [obviously after checking "unknown sources" option]; I am not able to get the location. I see in app setting, permission is there to access location on mobile. Also, When event is trigerred it shows GPS symbol on top bar but it disappears.
Can anybody help me with this?
Below is the code for location in my controller.js
.directive('reverseGeocode', function ($cordovaGeolocation, $rootScope) {
return {
restrict: 'E',
template: '<div></div>',
link: function (scope, element, attrs) {
var geocoder = new google.maps.Geocoder();
var posOptions = {timeout: 10000, enableHighAccuracy: true};
$cordovaGeolocation
.getCurrentPosition(posOptions)
.then(function (position) {
var lati = position.coords.latitude;
var longi = position.coords.longitude;
// console.log(angular.toJson($rootScope.lati) + " - " );
var request = new XMLHttpRequest();
var method = 'GET';
//var url = 'http://maps.googleapis.com/maps/api/geocode/json?latlng='+lat+','+long+'&sensor=true';
var async = true;
//alert(url);
//request.open(method, url, async);
//alert(angular.toJson(request.open(method, url, async)));
// var data = JSON.stringify(request.responseText);
// alert(JSON.stringify(request.responseText));
var latlng = new google.maps.LatLng(lati, longi);
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
//alert(results[1].address_components[1].long_name);
$rootScope.colony = results[1].address_components[1].long_name;
//alert(results[1].address_components[1].long_name);
//alert(results[1].address_components[1].long_name);
//alert(angular.toJson(results[1].address_components[1].long_name));
element.text(results[1].formatted_address);
} else {
element.text('Location not found');
}
} else {
element.text('Geocoder failed due to: ' + status);
}
});
}, function(err) {
// error
});
var watchOptions = {
frequency : 1000,
timeout : 3000,
enableHighAccuracy: false // may cause errors if true
};
var watch = $cordovaGeolocation.watchPosition(watchOptions);
watch.then(
null,
function(err) {
// error
},
function(position) {
var lat = position.coords.latitude
alert("abc >>" + lat);
var long = position.coords.longitude
});
watch.clearWatch();
// OR
$cordovaGeolocation.clearWatch(watch)
.then(function(result) {
// success
}, function (error) {
// error
});
},
replace: true
}
})
In html file I am using it as :
<h6>
User Colony: {{ colony }}
<reverse-geocode lat={{lati}} lng={{longi}}></reverse-geocode>
</h6>
<a href="#" ng-click="showStores(colony)" class="button button-block button-positive">
Browse Store
</a>
which triggeres the directive and find lat and long of user.
When testing on browser, it works perfectly but not on mobile itself.
In android it is super complicated to work with the GPS user, remember that often the geolocation we get is from the browser and not the GPS itself, and this varies a lot in the devices. For your help, I recommend installing cordova.plugins.diagnostic
function onDeviceReady() {
cordova.plugins.diagnostic.isLocationAuthorized(function(enabled){
//alert("gps es : " + (enabled ? "enabled" : "disabled"));
}, function(error){
//alert("error: "+error);
});
cordova.plugins.diagnostic.isLocationEnabled(function(enabled){
if(!enabled){
alert("gps not actived");
}else{
navigator.geolocation.getCurrentPosition(onSuccess, onError, {enableHighAccuracy: true,timeout: 5000,maximumAge: 5000});
}
}, function(error){
console.log("The following error occurred: "+error);
});
}
Always trying to see if I can get a latitude and longitude and if that is not activated or not you can get, it sends a message to the user. I hope it helps you.