Mobile Apps with Phonegap and Yeoman

Link to github repository

I’ve been building mobile-first web applications for some time now, and I want to describe my development process from start to finish (including deploying to the web, to iOS, and to Android devices). To start, I develop using a macbook pro, sublime text 2, and terminal. I would suggested either installing these, or similar tools you are familiar with.

I will be building a timer app - starting with a blank application, to web application, to mobile applications. My framework for this demonstration will be using angularjs, but simply replace these packages and angular references with what you want to use.

Basic app running Basic app running Basic app running

Setup

Install these tools:

consider installing both yeoman and phonegap packages globally

npm install -g yo
npm install -g cordova

Next lets create our application structure using the following ‘cordova’ command. I’ll call my app ‘timer’. Make sure you are using node version 0.10

nvm use 0.10
cordova create timer com.lpprojects.timerapp "TimerApp" /** the com.company.appname is like a backwards web domain naming convention for mobile apps **/
cd timer
cordova platform add ios /**add platforms you want to support here**/

Now it’s time to use Yeoman to scaffold a basic angular application.

Please Note: yeoman allows you to scaffold apps using many frameworks

Run the following (replace angular with your framework of choice):

yo angular

Yeoman will ask you a series of questions related to the package you requested(see below). I will not be using these options.

Would you like to include Twitter Bootstrap? (Y/n) n
If so, would you like to use Twitter Bootstrap for Compass (as opposed to vanilla CSS)? (Y/n) n
Would you like to include angular-resource.js? (Y/n) n
Would you like to include angular-cookies.js? (Y/n) n
Would you like to include angular-sanitize.js? (Y/n) n

Now that your scaffolded app is complete, lets take a look at what it generated:

Refer to http://Yeoman.io for any additional Yeoman questions I don’t cover in this post.

Configuring

Now we can view the default application by running:

grunt server

This will launch a live-reload web server

Next I want to use some additional javascript libraries not included in the scaffold. To add these, open the component.json file, and modify the file to your liking.

Yeoman scaffolding uses an older versions of angular, so I will upgrade that first. This process is important for understanding how to manage all your development packages from one place.

component.json

Before

{
  "name": "timerApp",
  "version": "0.0.0",
  "dependencies": {
    "angular": "~1.0.5",
    "json3": "~3.2.4",
    "es5-shim": "~2.0.8"
  },
  "devDependencies": {
    "angular-mocks": "~1.0.5",
    "angular-scenario": "~1.0.5"
  }
}

After

{
  "name": "timerApp",
  "version": "0.0.0",
  "dependencies": {
    "angular": "~1.2.0",
    "json3": "~3.2.4",
    "es5-shim": "~2.0.8"
  },
  "devDependencies": {
    "angular-mocks": "~1.2.0",
    "angular-scenario": "~1.2.0"
  }
}

Run the following command to install these packages:

bower install

The new version of angular broke the generated code, time to fix this.

Adding dependencies

In the new angular version, The ngRoute module was removed from the core project (angular.js) and I now need to include that as a seperate dependency. I will add the file to my component.json and install it.

The other three dependencies will be used to enhance the mobile development.

Add to “dependencies” in component.json

"angular-route": "~1.2.0",
"angular-localstorage": "latest",
"angular-bootstrap": "latest",
"sass-bootstrap": "~2.3"

Run in terminal

bower install

next I need to include the file on the page so in index.html I add it under the angular.js reference:

index.html

<script src="components/angular-route/angular-route.js"></script>
<script src="components/angular-localstorage/localStorageModule.js"></script>
<script src="components/angular-bootstrap/ui-bootstrap-tpls.js"></script>

app.js

finally add the dependencies into my angular application in app.js. see the [‘ngRoute’] is the loaded dependency

angular.module('timerApp', ['ngRoute', 'ui.bootstrap', 'LocalStorageModule'])

NOTE: adding Angular dependencies is a useful process to remember if using angularjs as your framework.

Developing

Now that I have setup my project, I’m going to start building my app.

Programming

Since I don’t want to focus on the actual writing of code, please take a look at my github repository for the timerApp code.

Build/Compile

First we need to add a node module called ‘grunt-shell’ so that we can integrate the cordova build task into our grunt build task. Open package.json and add the following line to the devDependencies

"grunt-shell": "latest"

Then run ‘npm install’ to install the package.

Next lets modify the gruntfile.js to support phonegap Add the Phonegap config property

var yeomanConfig = {
  app: 'app',
  dist: 'dist',
  phonegap: 'www'
};

Now we need to add the configuration for the phonegap build task

shell: {
  phonegapBuild: {
    command: 'cordova build'
  }
}

By default phonegap expects your application to live in www folder, so we will use that. Next we will modify the clean task to account for the new phonegap directory

clean: {
  dist: {
    files: [{
      dot: true,
      src: [
        '.tmp',
        '<%= yeoman.dist %>/*',
        '!<%= yeoman.dist %>/.git*'
      ]
    }]
  },
  phonegap: ['<%= yeoman.phonegap %>/*', '!<%= yeoman.phonegap %>/config.xml', '!<%= yeoman.phonegap %>/res'],
  server: '.tmp'
}

When we clean the build, it will delete everything but the phonegap config.xml, and the res directory with icons and splash screen images. Next lets modify the copy task, adding the phonegap sub task.

copy: {
  dist: {
    files: [{
      expand: true,
      dot: true,
      cwd: '<%= yeoman.app %>',
      dest: '<%= yeoman.dist %>',
      src: [
        '*.{ico,txt}',
        '.htaccess',
        'data/*.json',
        '*.html',
        'views/*.html',
        'components/**/*',
        'images/{,*/}*.{gif,webp}',
        'styles/fonts/*'
      ]
    }]
  },
  phonegap: {
    expand: true,
    cwd: '<%= yeoman.dist %>',
    dest: '<%= yeoman.phonegap %>',
    src: '**'
  }
}

Now, the build task will need to make use of the changes above. I prefer to make use of the target paramater when running ‘grunt build:target’.

grunt.registerTask('build', 'build task', function(target) {
  target = target || 'dev';
  if (target === 'phonegap') {
    grunt.task.run([
      'clean:phonegap',
      'clean:dist',
      'jshint',
      'test',
      'coffee',
      'compass:dist',
      'imagemin',
      'cssmin',
      'htmlmin',
      'copy',
      'cdnify',
      'ngmin',
      'uglify',
      'rev',
      'copy:phonegap',
      'shell:phonegapBuild'
    ]);
  } else {
    grunt.task.run([
      'clean:dist',
      'jshint',
      'test',
      'coffee',
      'compass:dist',
      'useminPrepare',
      'imagemin',
      'cssmin',
      'htmlmin',
      'concat',
      'copy',
      'cdnify',
      'ngmin',
      'uglify',
      'rev',
      'usemin'
    ]);
  }
});

Please note for the else condition, I moved the ‘concat’ task before ‘imagemin’ because it causes css compile issues otherwise. For the phonegap build, I don’t want to minify the scripts for debugging purposes.

you will notice, when we pass ‘phonegap’ as the target, it simply cleans the phonegap directory, builds the app, and copies the re-build code to the phonegap directory. The last command build the actual ios application.

To build the web app, simply run

grunt build

And to build the phonegap app run

grunt build:phonegap

Debugging

For the web

grunt server

with your favorite browser (mine is chrome)

For ios once the phonegap application is build you can run using:

cordova emulate ios

or by opening the xcode project file - appName/platforms/ios/appName.xcodeproj (instructions)

once the simulator is up and running, open up Safari and go to Develop -> iPhone Simulator -> index.html

Use the device

Now for the most useful and important part of using phonegap - use the device features Here is the phonegap list of features. In timer app, I will be making use of the vibration features.

When the mobile app is built, a cordova.js file is injected into the root directory. For simplicity, we will just include the reference in our index.html file. This will need to go within the head section of the index.html file.

<script src="cordova.js"></script>

Next lets fire the correct events in our app when we want. The vibration api can show us what we need to include.

navigator.notification.vibrate(2500);

In main.js I refer to this call. Now for some device specific features, they are only useable on an actual device (vibrate, beep), but other features like contacts, alert and so on is still useable just with the simulator.

Conclusion

Thats all you need to start developing phonegap mobile apps. Just remember, the libraries and tools I use will surely be upgraded as time goes on, keep that in mind when following my instructions. If you have any questions, confusions or suggestions please feel free to leave a message below. Happy mobile app development!

Back