Background geolocation in Ionic app

This blog show an example on how to implement background geolocation in an Ionic app using the background geolocation plugin.  to capture user locations for building location aware applications

Install plugin

First add the cordova plugin to the Ionic app:

cordova plugin add cordova-plugin-mauron85-background-geolocation

Implement background geolocation service

Next, implement an Angular service:

var app = angular.module('starter');
app.factory('BackgroundGeolocationService', ['$q', '$http', function ($q, $http) { 
      var callbackFn = function(location) {
          postLocation(location);
          backgroundGeoLocation.finish();  
      },
      failureFn = function(error) {
          console.log('BackgroundGeoLocation error ' + JSON.stringify(error));  
      },

      //Enable background geolocation  
      start = function () {      
          //save settings (background tracking is enabled) in local storage    
          window.localStorage.setItem('bgGPS', 1);
          backgroundGeoLocation.configure(callbackFn, failureFn, {
               desiredAccuracy: 10,      
               stationaryRadius: 10,
               distanceFilter: 10,
               locationProvider: 'ANDROID_ACTIVITY_PROVIDER',
               interval: 10000,      
               fastestInterval: 5000,      
               stopOnStillActivity: false,
               debug: false,      
               stopOnTerminate: false
         });
         backgroundGeoLocation.start();
      };
     // Send location to a backend server, e.g. for location tracking
     postLocation = function post(location) {
         return $http(      
           {        
              method: 'POST',
              headers: {
                   "Content-Type": "application/json"
                    },
              url: 'http://<location server DNS>/location',
              data: {          
                    lat : location.latitude,
                    lng : location.longitude        
                    }      
           }).then(function (response) {
                   return response.data;      
           });  
       }
  
       return {    
            start: start,
            // Stop data tracking    
            stop: function () {
                window.localStorage.setItem('bgGPS', 0);
                backgroundGeoLocation.stop();    
            }  
      }
}]);

The codes above are largely based on this blog article.  I have modified the plugin configuration (see notes below). Details about each configuration parameter can be found in the plugin documentation. I am setting it up and tested for Android here. A few notes or tips below:

  1. Two location providers are supported in Android – Android_distance_filter_provider and Android_activity_provider. I end up using the 2nd one to adjust the intervals in which the app gets location update by setting the parameters interval and fastinterval (to 10 and 5 seconds respectively).
  2. Debug is your friend. Set this to true will trigger a sound and notification when the app receives a location update.
  3. I use a combination of parameters desiredAccuracy, stationaryRadius and distanceFilter to define how often the app should receive location update events. The values set here seems to strike a good balance between accuracy/frequency and battery usage but its largely depends on the app’s use cases and phones.
  4. The plugin includes a url paramter where you can set to the backend server to post the locations. It is also possible, and more flexible, to just implement your own method and call it in the callback function callbackFn 

To kick start the plugin, call init() method in the app.js :

angular.module('app', ['ionic', ...])
.run(function($ionicPlatform, $http, BackgroundGeolocationService) {
   $ionicPlatform.ready(function() {    
       if(window.StatusBar) {
          StatusBar.styleDefault();
       }
       BackgroundGeolocationService.init();
   });
});

Now the Ionic app can send geolocations events when it is in the background, it is rather straight forward to implement a backend server to track and display users’ current locations. Below is a screenshot of a Java app I build, for example:

blog_track.png

 

Integrate Docker with Maven for Spring Boot projects

This blog will demonstrate how to setup in Maven using a number of plugins to integrate Docker in a Spring Boot Maven project. The objective here is to rebuild the docker image for the project seamlessly whenever Maven is run to build and release a new jar file.

The source codes for this project can be found in here

POM File

The project pom.xml file build life cycle is updated to include 3 plugins as shown below:

<build>
 <plugins>
    <plugin>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    <plugin>
       <artifactId>maven-resources-plugin</artifactId>
       <executions>
          <execution>
             <id>copy-resources</id>
             <phase>process-resources</phase>
             <goals>
                 <goal>copy-resources</goal>
             </goals>
             <configuration>
               <outputDirectory>${basedir}/target</outputDirectory>
               <resources>
                  <resource>
                     <directory>src/main/resources/docker</directory>
                     <includes>
                        <include>Dockerfile</include>
                     </includes>
                  </resource>
               </resources>
             </configuration>
           </execution>
        </executions>
     </plugin>
     <plugin>
        <groupId>com.google.code.maven-replacer-plugin</groupId>
        <artifactId>replacer</artifactId>
        <version>1.5.3</version>
        <executions>
            <execution>
               <phase>prepare-package</phase>
               <goals>
                   <goal>replace</goal>
               </goals>
            </execution>
        </executions>
        <configuration>
             <file>${basedir}/target/Dockerfile</file>
             <replacements>
                 <replacement>
                     <token>IMAGE_VERSION</token>
                     <value>${project.version}</value>
                 </replacement>
             </replacements>
         </configuration>
     </plugin>
     <plugin>
         <groupId>com.spotify</groupId>
         <artifactId>dockerfile-maven-plugin</artifactId>
         <version>${version.dockerfile-maven}</version>
    <executions>
       <execution>
       <id>default</id>
       <goals>
          <goal>build</goal>
          <goal>push</goal>
       </goals>
       </execution>
     </executions>
     <configuration>
          <contextDirectory>${project.build.directory}</contextDirectory>
          <repository>image name here</repository>
          <tag>${project.version}</tag>
     </configuration>
    </plugin>
  </plugins>
</build>

The pom file assumes the Dockerfile can be found in the source folder /src/resource/docker. You can define your own Dockerfile as needed for your project. For demo purpose, I am using, with minor modification, the sample Dockerfile found in this blog

FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD docker-maven-IMAGE_VERSION.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

Note the tag IMAGE_VERSION, this will be replaced with the version of the jar file being built

The first step in the build is to copy the Dockerfile above to the /target, i.e. build output, folder using the resource plugin. This is needed for 2 reasons: (1) we need to set the filename to add to the image to match that of the version being built and (2) Docker does not allow in ADD source file outside of the context directory of the Dockerfile so we have to put it in same directory as the jar file.

The second step is to set in the Dockerfile just copied the correct version of the jar file to be included in the docker image. The Maven Replacer plugin is used to replace the tag IMAGE_VERSION in the Dockerfile with the Maven variable project.version.

Finally, we run the Spotify Dockerfile Maven plugin to build/push the docker image. The plugin allows you to set what repository to use. Note we set the tag to be that of the Maven variable project.version as in step 2 to make sure that the image tag matches that of the jar file.

Running Maven

Now whenever the project is build or deploy in Maven using the standard mvn install or mvn deploy, the corresponding docker image will also be build or pushed to the repository. This also works for mvn release:prepare and mvn release:prepare for releasing tag version of the jar file.

Note you would need to setup certificate required to access the Docker daemon. For example, include the following environment variables:

DOCKER_HOST // to <host ip address>
DOCKER_TLS_VERIFY = true
DOCKER_CERT_PATH = C:\Users\<username>\.docker\machine\certs

Consult Docker documentation for more details on secure access to the Docker daemon.

Below is an excerpt of what you would see in a console when running mvn install

[INFO] ------------------------------------------------------------------------
[INFO] Building docker-maven 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
[INFO] --- maven-resources-plugin:2.6:copy-resources (copy-resources) @ docker-maven ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ docker-maven ---
...
[INFO] --- replacer:1.5.3:replace (default) @ docker-maven ---
[INFO] Replacement run on 1 file.
[INFO] 
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ docker-maven ---
[INFO] Building jar: D:\src\blog_docker_maven\target\docker-maven-0.0.1-SNAPSHOT.jar
...
[INFO] Image will be built as <image name here>
[INFO] 
[INFO] Step 1/7 : FROM frolvlad/alpine-oraclejdk8:slim
[INFO] Pulling from frolvlad/alpine-oraclejdk8
...