Ionic + ngCordova + background geolocation + DeviceReady issue

Issue

I’m trying to get the background geolocation plugin to work in my app; however, the page only sometimes loads on my device when I use the deviceready function. From my googling, it seems that I should be using $ionicPlatform.ready instead, but $cordovaBackgroundGeolocation is undefined when I try to do that. Similarly, the device is always undefined when I try to do anything with it.

I also tried manually bootstrapping angular, that didn’t work; and I tried simply running the function without putting it inside deviceready or $ionicPlatform.ready or anything; that didn’t work either.

The code in question:

Controller:

// Define the angular module
angular.module('testApp.controllers', ['ionic', 'ngCordova.plugins.geolocation', 'ngCordova.plugins.backgroundGeolocation'])

.controller('MapCtrl', ['$scope', '$ionicPopup', '$cordovaGeolocation', '$cordovaBackgroundGeolocation', '$timeout', '$http', '$ionicPlatform', 
               function ($scope, $ionicPopup, $cordovaGeolocation, $cordovaBackgroundGeolocation, $timeout, $http, $ionicPlatform) {
    $scope.loaded = false;

    var posOptions = { timeout: 5000, enableHighAccuracy: true, maximumAge: 5000 };
    $cordovaGeolocation.getCurrentPosition(posOptions)
        .then(function (location) {
            $scope.currentLat = location.coords.latitude;
            $scope.currentLong = location.coords.longitude;
            $scope.loaded = true;
        });

    $ionicPlatform.ready(function() {
        var bgGeo = $cordovaBackgroundGeolocation;

        // BackgroundGeoLocation is highly configurable.
        bgGeo.configure({
            url: 'http://www.my_api_url_here/',
            params: {
                deviceId: "testApp",
                "location": {
                    "latitude": "38.896339999999995",
                    "longitude": "-77.08521460000001"
                }
            },
            desiredAccuracy: 10,
            stationaryRadius: 20,
            distanceFilter: 30,
            notificationTitle: 'TestTitle', // <-- android only, customize the title of the notification
            notificationText: 'TestText', // <-- android only, customize the text of the notification
            activityType: 'OtherNavigation',
            debug: true, // <-- enable this hear sounds for background-geolocation life-cycle.
            stopOnTerminate: false // <-- enable this to clear background location settings when the app terminates
        });

        bgGeo.start();
    });
}])

Directive:

.directive('bgeo', ['$cordovaGeolocation', '$cordovaBackgroundGeolocation', '$http', 
           function ($cordovaGeolocation, $cordovaBackgroundGeolocation, $http) {
    return {
        scope: {
           lat: '=',
           lng: '='
       },
        link: function (scope) {
            console.log("directive: ", scope.lat, scope.lng);
                myLatLng = new google.maps.LatLng(scope.lat, scope.lng);
                mapOptions = {
                    zoom: 16,
                    center: myLatLng
                };
                map = new google.maps.Map(document.getElementById('map'), mapOptions);
                marker = new google.maps.Marker({
                    position: myLatLng,
                    map: map,
                    draggable: false,
                    icon: 'small-orange-pin.png'
                });
        }
    }
}])

Template:

<ion-scroll zooming="true" direction="xy" style="width:90%">
   <div ng-if="loaded" bgeo lat="currentLat" lng="currentLong">
       <div id="map" style="width: 600px; height: 500px;"></div>
   </div>
</ion-scroll>

app.js run method:

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }

    if (window.cordova) {
      if (window.plugins && window.plugins.backgroundGeoLocation) {
        BackgroundGeolocation.configurePlugin(window.plugins.backgroundGeoLocation);
      }
    }
  });
})

The full source code is up on github at https://github.com/sahiltalwar88/binding-geolocation-issue. Any help is much appreciated!

Solution

The main issue was that I had to run bower install; I was missing several packages. Once I did that, I could use the ionic ready function and onDeviceReady just fine. Then, in order to get the iOS callback functions working, I had to update my syntax to work with ngCordova (which uses Q and promises) rather than callback functions, as the examples showed.

Here’s the structure of my final code:

$ionicPlatform.ready(function() {
if(window.StatusBar) {
  StatusBar.styleDefault();
}

$location.path('/app');
$rootScope.$digest();

$rootScope.deviceReady = false; 

document.addEventListener('deviceready', function () {
    if(window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
      window.cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }

    var bgGeo = $cordovaBackgroundGeolocation;
    var deviceId = $cordovaDevice.getUUID();
    var addVisitUrl = 'your-url-goes-here';

    $rootScope.deviceId = deviceId;
    $rootScope.deviceReady = true;

    var posOptions = { timeout: 5000, enableHighAccuracy: true, maximumAge: 5000 };
    $cordovaGeolocation.getCurrentPosition(posOptions)
        .then(function (location) {
            $rootScope.currentLat = location.coords.latitude;
            $rootScope.currentLong = location.coords.longitude;

            var yourAjaxCallback = function(response) {
                bgGeo.finish();
            };

            var callbackFn = function(location) {
                var data = {
                                deviceId: deviceId,
                                "location": {
                                    "latitude": location.latitude,
                                    "longitude": location.longitude
                                }
                            };
                $http.post(addVisitUrl, data);
                // Other code goes here

                yourAjaxCallback.call(this);
            };

            var failureFn = function(error) {
                alert('Background Geolocation Error: ' + error);
                // Other code goes here
            };

            bgGeo.configure({
                url: addVisitUrl,
                params: {
                    deviceId: deviceId,
                    "location": {
                        "latitude": $rootScope.currentLat,
                        "longitude": $rootScope.currentLong
                    }
                },
                desiredAccuracy: 10,
                stationaryRadius: 10,
                distanceFilter: 10,
                activityType: 'OtherNavigation',
                debug: true, 
                stopOnTerminate: false
            })
            .then(callbackFn, failureFn, callbackFn);

            bgGeo.start();
        });
    $rootScope.$digest();
    });
  });
})

Answered By – Sahil Talwar

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published