Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Mastering PhoneGap Mobile Application Development

You're reading from   Mastering PhoneGap Mobile Application Development Take your PhoneGap experience to the next level and create engaging real-world applications

Arrow left icon
Product type Paperback
Published in Feb 2016
Publisher
ISBN-13 9781783288434
Length 392 pages
Edition 1st Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Kerri Shotts Kerri Shotts
Author Profile Icon Kerri Shotts
Kerri Shotts
Arrow right icon
View More author details
Toc

Table of Contents (14) Chapters Close

Preface 1. Task Automation FREE CHAPTER 2. ECMAScript 2015 and Browserify 3. Sassy CSS 4. More Responsive Design 5. Hybrid Application Accessibility 6. Testing and UI Automation 7. IndexedDB 8. Web SQL Database 9. Transferring Files 10. Performance 11. Graphical Assets 12. Deployment Index

How to execute Cordova tasks

It's tempting to use the Cordova command-line interface directly, but there's a problem with this: there's no great way to ensure what you write works across multiple platforms. If you are certain you'll only work with a specific platform, you can go ahead and execute shell commands instead; but what we're going to do is a bit more flexible.

Note

The code in this section is inspired by https://github.com/kamrik/CordovaGulpTemplate.

The Cordova CLI is really just a thin wrapper around the cordova-lib project. Everything the Cordova CLI can do, cordova-lib does as well.

Because the Cordova project will be a build artifact, we need to be able to create a Cordova project in addition to building the project. We'll also need to emulate and run the app. To accomplish this, we'll need to create a new utility file named gulp/utils/cordova-tasks.js. At the top we require cordova-lib and other packages we'll need:

var cordovaLib = require("cordova-lib"),
    pkg = require("../../package.json"),
    config = require("../config"),
    path = require("path"),
    settings = require("../settings"),
    paths = require("../utils/paths");
var cordova = cordovaLib.cordova.raw;

Next, let's create the code to create a new Cordova project in the build directory:

var cordovaTasks = {
  // CLI: cordova create ./build com.example.app app_name
  //              --copy-from template_path
  create: function create() {
    return cordova.create(paths.makeFullPath(".", paths.DEST), 
      pkg.cordova.id, pkg.cordova.name,
      {
        lib: {
          www: {
            url: path.join(process.cwd(), pkg.cordova.template),
            link: false
          }
        }
      });
  }
}
module.exports = cordovaTasks;

Although it's a bit more complicated than cordova create is on the command line, you should be able to see the parallels. The lib object is passed simply to provide a template for the project (equivalent to --copy-from on the command line). In our case, package.json specifies that this should come from the blank/ directory in the code bundle of this book. If we don't do this, all our apps would be created with the sample Hello World app that Cordova installs by default.

Note

Our blank project template resides in ../blank relative to the project root. Yours may reside elsewhere (since you're apt to reuse the same template), so package.json can use whatever path you need. Or, you might want the template to be within your project's root; in which case, package.json should use a path inside your project's root directory.

We won't create a task to use this just yet. We need to define several other methods to build and emulate the Cordova app. First, we need to add some additional settings to gulp/settings.js:

var settings = { …,
  PLATFORM = gutil.env.platform ? gutil.env.platform :"ios",
  BUILD_MODE = gutil.env.mode ? gutil.env.mode :"debug",
  BUILD_PLATFORMS = (gutil.env.for ? gutil.env.for
                                   : "ios,android").split(","),
  TARGET_DEVICE = gutil.env.target ? "--target=" +
                  gutil.env.target : ""
}

Next, let's continue to add the additional methods we need to the cordovaTasks object:

var cordovaTasks = {
  create: function create() {
    /* as above */
  },
  cdProject: function cdProject() {
    process.chdir(paths.makeFullPath("www", paths.DEST));
  },
  cdUp: function cdUp() {
    process.chdir("..");
  },
  // cordova plugin add ...
  addPlugins: function addPlugins() {
    cordovaTasks.cdProject();
    return cordova.plugins("add", pkg.cordova.plugins)
      .then(cordovaTasks.cdUp);
  },
  // cordova platform add ...
  addPlatforms: function addPlatforms() {
    cordovaTasks.cdProject();
    function transformPlatform(platform) {
      return path.join(process.cwd(), "node_modules",
        "cordova-" + platform);
    }
    return cordova.platforms("add",
      pkg.cordova.platforms.map(transformPlatform))
      .then(cordovaTasks.cdUp);
  },
  // cordova build <platforms> --release|debug
  //                           --target=...|--device
  build: function build() {
    var target = settings.TARGET_DEVICE;
    cordovaTasks.cdProject();
    if (!target || target === "" ||
      target === "--target=device") {
      target = "--device";
    }
    return cordova.build({
      platforms: settings.BUILD_PLATFORMS,
      options: ["--" + settings.BUILD_MODE, target]
    }).then(cordovaTasks.cdUp);
  },
  // cordova emulate ios|android --release|debug
  emulate: function emulate() {
    cordovaTasks.cdProject();
    return cordova.emulate({
      platforms: [settings.PLATFORM],
      options: ["--" + settings.BUILD_MODE, 
        settings.TARGET_DEVICE]
    }).then(cordovaTasks.cdUp);
  },
  // cordova run ios|android --release|debug
  run: function run() {
    cordovaTasks.cdProject();
    return cordova.run({
      platforms: [settings.PLATFORM],
      options: ["--" + settings.BUILD_MODE, "--device",
        settings.TARGET_DEVICE]
    }).then(cordovaTasks.cdUp);
  },
  init: function() {
    return cordovaTasks.create()
      .then(cordovaTasks.copyConfig)
      .then(cordovaTasks.addPlugins)
      .then(cordovaTasks.addPlatforms);
  }
};

Note

If you aren't familiar with promises, you might want to learn more about them. http://www.html5rocks.com/en/tutorials/es6/promises/ is a fantastic resource.

Most of the previous tasks should be fairly self-explanatory; they correspond directly to their Cordova CLI counterparts. A few, however, need a little more explanation:

  • cdProject / cdUp: These change the current working directory. All the cordova-lib commands after create need to be executed from within the Cordova project directory, not our project's root directory. You should notice them in several of the tasks.
  • addPlatforms: The platforms are added directly from our project's dependencies, rather than from the Cordova CLI. This allows us to control the platform versions we are using. As such, addPlatforms needs to do a little more work to specify the actual directory name of each platform.
  • build: This executes the cordova build command. By default, CLI builds every platform. Since we will want to control the platforms that are built, hence we can use BUILD_PLATFORMS to control this behavior. On iOS, the build for an emulator is different than the build for a physical device. So, we also need a way to specify this, which is what TARGET_DEVICE does. This will look for emulators with the name specified for TARGET_DEVICE. But we might want to build for a physical device; in which case, we will look for device (or no target specified at all) and switch over to the --device flag which forces Cordova to build for a physical device.
  • init: This does the hard work of creating the Cordova project, copying the configuration file (and performing substitutions), adding plugins to the Cordova project, and then adding platforms.

Now is also a good time to mention that we can specify various settings with switches on the Gulp command line. In the earlier snippet, we're supporting the use of --platform to specify the platform to emulate or run, --mode to specify the build mode (debug or release), --for to determine what platforms Cordova will build for, and --target to specify the target device. The code will specify reasonable defaults if these switches aren't specified; but they also allow the developer extra control over the workflow, which is very useful. For example, we'll be able to use commands like the following:

$ gulp build --for ios,android --target device
$ gulp emulate --platform ios --target iPhone-6s
$ gulp run --platform ios --mode release

Next, let's write the code to actually perform various Cordova tasks. It isn't difficult, but we need to create a lot of files. Each file name in the code below is in comments:

// gulp/tasks/clean.js
var paths = require("../utils/paths"),
    config = require("../config"),
    rimraf = require("rimraf");
function clean(cb) {
    var BUILD_PATH = paths.makeFullPath(".", paths.DEST);
    rimraf(BUILD_PATH, cb);
}
module.exports = {
    task: clean
}

// gulp/tasks/init.js
var cordovaTasks = require("../utils/cordova-tasks");
module.exports = {
  deps: ["clean"],
  task: cordovaTasks.init
};

// gulp/tasks/build.js
var cordovaTasks = require("../utils/cordova-tasks");
module.exports = {
  deps: ["copy"],
  task: cordovaTasks.build
};

// gulp/tasks/emulate.js
var cordovaTasks = require("../utils/cordova-tasks");
module.exports = {
  deps: ["copy"],
  task: cordovaTasks.emulate
};

// gulp/tasks/run.js
var cordovaTasks = require("../utils/cordova-tasks");
module.exports = {
  deps: ["copy"],
  task: cordovaTasks.run
};

There's a catch with the init task: it will fail if anything is already in the build/ directory. As you can guess, this could easily happen; so we also created a clean task. This uses rimraf to delete a specified directory, which is equivalent to using rm -rf build. We then ensured that init depends on clean. So, whenever we execute gulp init, the old Cordova project is removed and a new one is created for us.

Finally, note that all the build (and other) tasks depend on copy. This means that all our files in src/ will be copied (and transformed, if necessary) to build/ prior to executing the desired Cordova command. As you can see, our tasks are already becoming very complex, while remaining comprehensible when they are taken singularly.

This means that we can now use the following tasks in Gulp:

$ gulp init                   # create the cordova project;
                              # cleaning first if needed
$ gulp clean                  # remove the cordova project
$ gulp build                  # copy src to build; apply
                              # transformations; cordova build
$ gulp build --mode release   # do the above, but build in
                              # release mode
$ gulp build --for ios        # only build for iOS
$ gulp build --target=device  # build device versions instead of
                              # emulator versions
$ gulp emulate --platform ios # copy src to build; apply
                              # transformations;
                              # cordova emulate ios
$ gulp emulate --platform ios --target iPhone-6
                              # same as above, but open the
                              # iPhone 6 emulator
$ gulp run --platform ios     # copy src to build;
                              # apply transformations;
                              # cordova run ios --device

Now, you're welcome to use the previous code as it is or you can use an NPM package that takes care of the cordovaTasks portion for you. This has the benefit of drastically simplifying your Gulp configuration. We've already included this package in our package.json file as well as our Gulp configuration. It's named cordova-tasks and was created by the author. It shares a lot of similarities to the earlier code. To see how it works (and how much simpler the tasks become), see logology-v01/gulp in the code package for this book.

This was one of the complex sections; so if you've come this far, take a coffee break. Next, we'll worry about managing app version numbers.

You have been reading a chapter from
Mastering PhoneGap Mobile Application Development
Published in: Feb 2016
Publisher:
ISBN-13: 9781783288434
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image