Do you feel the motion? No? Then you’re not using ngCordova device motion plugin. I’m creating this example to show you how easy it is.
 
 

Note: If this tutorial was helpful, need further clarification, something is not working or do you have a request for another Ionic post? Furthermore, if you don't like something about this blog, if something is bugging you, don't like how I'm doing stuff here, again leave me a comment below. I'm here to help you, I expect the same from you. Feel free to comment below, subscribe to my blog, mail me to dragan.gaic@gmail.com, or follow and mention me on twitter (@gajotres). Thanks and have a nice day!

PS. If you want my help, if possible (even if it takes you some time to do that), create a working example I can play with. Use Plunker for AngularJS based questions or jsFiddle for jQuery/jQuery Mobile based questions.


 

Table of Contents

 
 
Click here if you want to see other tutorials, or articles about the Ionic framework (themes, templates, plugins, tutorials)
 

Preparation

 
This tutorial requires a correct development environment:
 
  • Android Environment (or iOS if your working on a MacOS)
  • nodeJS
  • Ionic
  • Cordova
If you don’t have previous Ionic Framework experience, find more information here: Ionic Framework | Installation Guide.
 

1. Update Ionic & Cordova

 
Before we can start make sure you have the latest nodeJS installation, without it, you’ll not be able to properly install Ionic and Cordova.
 
If everything went well with nodeJS, let’s continue with Ionic and Cordova:
 
npm update -g cordova ionic
 

2. Create a New Project

 
ionic start IonicDeviceMotionDemo blank
cd IonicDeviceMotionDemo
 
Warning: Since some of you never worked with Ionic CLI. From this point and further, every time I tell you to execute something, do that inside a project folder.
 
This example requires Android platform:
 
ionic platform add android
 
For MacOS users, do it like this:
 
ionic platform add ios
 

3. Download ngCordova archive

 
ngCordova is a collection of 63+ AngularJS extensions on top of the Cordova API that make it easy to build, test, and deploy Cordova mobile apps with AngularJS. While we can make this work without ngCordova, it’s much more practical this way. This collection also holds many Ionic Framework compatible plugins.
 
Download ngCordova zip file, here’s site link:
 
Official Site Docs Download Link
 
 
Unzip this archive, find a file name called: ng-cordova.min.js, it should be available at this location: ng-cordova-master\dist\.
 
Open your newly created project directory and copy ng-cordova.min.js to this location: IonicDeviceMotionDemo\www\js.
 
Now include this location to index.html located at IonicDeviceMotionDemo\www; add it above cordova.js file, like this:
 
<!-- cordova script (this will be a 404 during development) -->
<script src="js/ng-cordova.min.js"></script>
<script src="cordova.js"></script>
 

4. Install Cordova Device Motion Plugin

 
Add required plugins:
 
cordova plugin add cordova-plugin-device-motion
cordova plugin add cordova-plugin-whitelist
 
Install Whitelist plugin only if you’re using Cordova 4.0 +. Without it you’ll receive “Application Error: There was a network error.” error. On the other hand, add last two plugins only if you’re intending to reuse my example. They’re not required for Image Picker.
 
GitHub - Device Motion
 
 
 

Development

 
At this point, you should have everything set up and ready, we can start working on our example.
 
Go to IonicDeviceMotionDemo project directory and find app.js, alter angular.module line and include ngCordova service, like this:
 
var app = angular.module('starter', ['ionic', 'ngCordova'])
 
Open index.html file, add a controller to ion-pane directive:
 
  <ion-pane>
      <ion-header-bar class="bar-stable">
        <h1 class="title">Device Motion Example</h1>
      </ion-header-bar>
      <ion-content ng-controller="MotionController">
      </ion-content>
   </ion-pane>
 
Initialize this controller in app.js file; don’t forget to inject $cordovaImagePicker service. We will also need $cordovaDeviceMotion, like this:
 
app.controller('MotionController', function($scope, $cordovaDeviceMotion, $ionicPlatform) {

});
 
If you’re using Cordova 4+, you will need to check if there’s a Whitelist plugin installed with your project. If you have it, add this security meta tag to your index.html HEAD content:
 
<meta http-equiv="Content-Security-Policy" content="default-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval' *; style-src  'self' 'unsafe-inline' *">
 
Without it your application will throw an error during the app initialization, after that it will continually throwing no security meta-tag found. While not a blocking point, constant console log warnings will make it hard to do any debugging.
 
Now let’s discuss our code, everything is described in comments:
 
    // watch Acceleration options
    $scope.options = { 
        frequency: 100, // Measure every 100ms
        deviation : 25  // We'll use deviation to determine the shake event, best values in the range between 25 and 30
    };

    // Current measurements
    $scope.measurements = {
        x : null,
        y : null,
        z : null,
        timestamp : null
    }

    // Previous measurements	
    $scope.previousMeasurements = {
        x : null,
        y : null,
        z : null,
        timestamp : null
    }
 
We will use next function to detect motion:
 
        //Start Watching method
        $scope.startWatching = function() {		

            // Device motion configuration
            $scope.watch = $cordovaDeviceMotion.watchAcceleration($scope.options);

            // Device motion initilaization
            $scope.watch.then(null, function(error) {
                console.log('Error');
            },function(result) {

                // Set current data  
                $scope.measurements.x = result.x;
                $scope.measurements.y = result.y;
                $scope.measurements.z = result.z;
                $scope.measurements.timestamp = result.timestamp;				  

                // Detecta shake  
                $scope.detectShake(result);  

            });		
        };	
 
Next function will stop motion detection:
 
        // Stop watching method
        $scope.stopWatching = function() {	
            $scope.watch.clearWatch();
        }	
 
Next function will detect shake event:
 
        // Detect shake method		
        $scope.detectShake = function(result) {	

            //Object to hold measurement difference between current and old data
            var measurementsChange = {};

            // Calculate measurement change only if we have two sets of data, current and old
            if ($scope.previousMeasurements.x !== null) {
                measurementsChange.x = Math.abs($scope.previousMeasurements.x, result.x);
                measurementsChange.y = Math.abs($scope.previousMeasurements.y, result.y);
                measurementsChange.z = Math.abs($scope.previousMeasurements.z, result.z);
            }

            // If measurement change is bigger then predefined deviation
            if (measurementsChange.x + measurementsChange.y + measurementsChange.z > $scope.options.deviation) {
                $scope.stopWatching();  // Stop watching because it will start triggering like hell
                console.log('Shake detected'); // shake detected
                setTimeout($scope.startWatching(), 1000);  // Again start watching after 1 sex

                // Clean previous measurements after succesfull shake detection, so we can do it next time
                $scope.previousMeasurements = { 
                    x: null, 
                    y: null, 
                    z: null
                }				

            } else {
                // On first measurements set it as the previous one
                $scope.previousMeasurements = {
                    x: result.x,
                    y: result.y,
                    z: result.z
                }
            }			

        }	
 
Continue to the next page

  • Jon

    Hi there.

    I wonder if you have any suggestions for re-starting the watch function after clearing it. I am using very similar code to your example in a controller for one tab in my app. When I navigate away from the tab, the watch stops as expected, but doesn’t re-start when I enter the tab again. I’ve tried turning off caching, but that seems to have even worse effects.

    • Waqas Hussain

      Hey Jon,
      Have you tried adding afterEnter event like below:

      $scope.$on(‘$ionicView.afterEnter’, function () {
      $scope.startWatching();
      });

      It works for me.

      • Jon Alling

        Yes, I think I got it to work now. Thanks!

  • Luke

    Hi,
    I ran your app on my phone (huawei p8lite) and I can’t see any measurements.
    This problem only occurs on my device. I tried other solutions but none of them worked, any idea how I can fix this?

    • To be honest, I don’t know what could be the problem. My advice, try debugging Cordova plugin, but from the Java side.

    • Ross Rawlins

      Did you figure this one out luke?

  • Tazaf

    Many, many thanks for this tutorial. It helped me a lot !
    (And it worked right away)

  • Awesome post, it helped me during one of my projects.
    I would only suggest to change the command to add the plugin to the new npm implementation

    cordova plugin add cordova-plugin-device-motion

  • Ross Rawlins

    Great implementation but where would you implement a call back for when the shake has ended?

  • Just followed this post to build in a shake function, works like a charm 🙂

  • Dan

    Hi there Gajotres,

    Just a note:

    // Calculate measurement change only if we have two sets of data, current and old
    if ($scope.previousMeasurements.x !== null) {
    measurementsChange.x = Math.abs($scope.previousMeasurements.x, result.x);
    measurementsChange.y = Math.abs($scope.previousMeasurements.y, result.y);
    measurementsChange.z = Math.abs($scope.previousMeasurements.z, result.z);
    }

    The comma does not get read in and instead, you are just checking the previousMeasurements values instead of change of values… the only change required is to put a minus ‘-‘ sign instead of the commas ‘,’ in this section of code and it will do what is was intended to do according to the rest of the program (otherwise, there is no point for current and previous measurements)

  • Dan

    On top of my previous point, you are not using the timestamp of previousMeasurements and not at all using the measurements object. That’s all I have noticed so far, I may be missing something…

  • Abdul Samad

    This is real nice and simple thanks for the awesome content

  • ELMER

    Thanks You so much! I tried this and It worked so good! 🙂