Skip to content

Platform Specific CSS/Javascript with Cordova CLI

Cordova CLI has a really good setup for merging in content that is platform specific under the www directory.

Basically, under the merges directory, you can place platform specific directories; mimic the names under platforms. Under that you can create directories named the same as directories under wwwcssor js, for example, and the files under those directories will be copied to the platforms build directories by the cordova prepare command.

The merges directory is useful, but limited.

When we had a Cordova app mocked up by a great phonegap consultancy, the end deliverable included large chunks of common css, but some platform specific CSS. Cordova CLI has no issue with this. Another use case would be presenting a common interface for plugins for different platforms that have slightly different APIs–you can write platform specific adapter objects, and place the platform specific javascript into merges. Here’s an article about another purpose for merges.

merges are limited, because only directories under www is merged. If there is anything else you want to modify that is outside of that directory (like, say, AndroidManifest.xml), well, you are out of luck.

Luckily, hooks come to the rescue again. In the next post, I will discuss how to update platform specific files using Cordova CLI.

Subscribe to my infrequent Cordova newsletter

Setting up CORS

So, this is not Cordova CLI specific, but being able to develop as much as possible in your web browser (with the quick feedback) is one of the benefits of Cordova, so I’ll cover it briefly.

If your data sources and your application are served from the same server (or proxied so that they look like they are) then you are good to go–no violation of the Same Origin Policy occurs.

If they are on different servers, then your browser is going to restrict access. However, if you aren’t sending any special headers and are only interested in reading data from your remote data source, or POSTing using limited mime types, you can get away with setting the Access-Control-Allow-Origin header to * on your data sever, and everything should work OK.

If you are using PUT, or sending special headers, or doing anything outside the box, you will want to preflight your requests with an OPTIONS header, as outlined here.

Basically, when a request comes in, you have to send back these headers:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER
Access-Control-Max-Age: 1728000

For development, the * for Access-Control-Allow-Origin is again fine. Note that if you specify a host and the server caches the response (if it is a proxying cache, for example) and you lock down Access-Control-Allow-Origin and more than one host tries to access this server, it will cause issues. Like, “the second request will fail” issues. This is not really a concern for development servers.

In addition, make sure that OPTIONS request can get through (another SO question I asked).

Note that this is only for development in the web browser (including ripple). Once you move to emulators and phones, you will be concerned about Cordova whitelists and not CORS.

In my next post, I will cover the merges directory.

Subscribe to my infrequent Cordova newsletter

Configuration management using Cordova CLI

Managing different builds of your Cordova application is relatively easy using hooks.

I actually have a number of deployment environments, all built from my local source tree.

  • web development, which lets me crank out the non cordova specific look and feel
  • test, which runs qunit/sinon unit tests
  • ripple development, which lets me run in the browser, but still test cordova specific events (online/offline, for example)
  • staging, which is used to build a phone distributable binary, but runs against our QA servers
  • production, the same as stage, but against our production servers

The first two don’t require a cordova prepare but the last three do. The first three let you make changes in files and reload your web browser, where the last two require a phone or emulator to run.

For a while I was switching between these manually, but eventually it became a pain, so I automated it. The automation is driven off an environment variable, which is accessed by a after_prepare hook: TARGET=stage cordova build android sets target to stage, and process.env.TARGET is the nodejs code in the hook script that can access that environment variable.

There is a config directory in the top level of the project and in there is a project.json file that contains project specific configuration for each target environment, like the server hostname.

One wrinkle that took me some time to figure out was how to have code that was in the www directory ‘just work’ out of the version control system, so I could do quick web development. In the end, I have code like this in my javascript files

App.config = {};
App.config.datahostname = /*REP*/'qa-host.com'/*REP*/;

and then this regular expression to replace it with the value from the configuration file when file is being prepared:

function replace_string_in_file(filename,to_replace,replace_with) {
  var data = fs.readFileSync(filename, 'utf8');
  var result = data.replace(new RegExp(to_replace,"g"), replace_with);
  fs.writeFileSync(filename, result, 'utf8');
}

...
// iterate over files to be updated with config info
replace_string_in_file(fullfilename,"/\\*REP\\*/'qa-host.com'/\\*REP\\*/",configobj[target].datahostname);

Note that I don’t read/write files async–this happens rarely enough that the performance increase isn’t worth some of the weirdness you will see if more than one hook acts on your file, or if you edit the file right after running the hook.

Since /*REP*/stuff/*REP*/ isn’t likely to match anything inadvertently, you could probably parse all your files, but my configuration is limited to 3-4 files, so it is easier just to name them explicitly.

Note that if during development, your javascript needs to access data served by a different web server (an API somewhere, for example), you’ll need to set up CORS correctly. We’ll set that up in the next blog post.

Subscribe to my infrequent Cordova newsletter

Hooks and Cordova CLI

Hooks are scripts that you can run before and after each stage of the Cordova CLI lifecycle. They live in a projecthome/.cordova/hooks/before_xxx (or after_xxx) where xxx is the project lifecycle stage (prepare, build, etc).

They are somewhat documented here, and here’s an example you can “borrow” from. As we’ll see in the next few posts, they are a lifesaver at dealing with some of the current deficiencies of Cordova CLI.

But to start with, all you need to know is that hooks are chunks of code that are passed the project base directory as the first argument (and therefore available via var rootdir = process.argv[2]; for node, or $1 for shell scripts). These chunks can be any kind of executable code (shell/node/perl/python/compiled c, etc). All I focus on here are project specific hooks–I don’t know how module hooks would work.

I have typically used hooks to move and manipulate files and used node (though you can use any scripting language) and am a node newbie–therefore stackoverflow and the node filesystem API docs were my friends.

Each hook is executed in alphabetical order within the before_ or after_ directory. A good idea is to name each hook to make the order explict:

  • 001_script
  • 010_script
  • 020_script
  • 120_script

executes scripts in the order you would expect, where:

  • 1_script
  • 10_script
  • 20_script
  • 120_script

does not.

In addition, if you write node scripts, consider using the synchronous versions of the file manipulation commands. While the default node commands (to move a file, say) are asynchronous, and therefore fast, for a build environment I have seen confusing results if I didn’t make everything synchronous. If you need the build process to be faster, then consider going async, but know what you are doing.

In the next post, I will discuss configuration for different environments.

Subscribe to my infrequent Cordova newsletter

Upgrading projects managed with Cordova CLI

I’d like to preface this post by saying that I’ve upgraded Cordova CLI 5-6 times on one project, but haven’t upgraded after submitting to any marketplace (the app store, etc) or after using plugins. I have, however, done some customization of the app.

Like I mentioned before, Cordova CLI is a moving target. So, you should be prepared to deal with upgrading your toolset. There are two types of updates–minor and major. Major will require more testing since APIs could change.

Just a heads up that 2.9.x is the last stable release of the 2.x codebase and the team has promised to support it for a long time (but not with new features). I have no idea how hard it will be to move a app from 2.9.x to 3.0.x, but I imagine there will be many plugins that won’t move to the new architecture, so I expect 2.9.x to be around for quite a while.

You can see if there is a new release of Cordova CLI by running npm outdated -g cordova.

To update either kind of release major release:

  1. Make sure that all your code is checked in (you are using version control, right)
  2. Move your old project directory to project.2.8.1
  3. Move your ~/.cordova directory to ~/cordova.2.8.1
  4. Checkout your project directory from your version control system
  5. Run npm update -g cordova@2.9.3
  6. Check out your project from source control
  7. cd project
  8. mkdir platforms; mkdir plugins
  9. cordova platforms add [your platforms]
  10. cordova plugins add [your plugins]
  11. continue development

This illustrates why it is so important to keep everything in version control. Because Cordova CLI controls the platforms and plugins directories, you have no idea what is happening in there, so any code or configuration that is in there should not be customized. For one thing, when you change versions of cordova, the cordova.js file that lives under platforms may or may not be changed–that’s why we re-add the platforms.

In my next post, I will discuss what hooks are.

Subscribe to my infrequent Cordova newsletter

Placing Cordova CLI projects under version control

If you do software development, you should use version control, and Cordova projects are no different. However, Cordova CLI generates a fair number of derived artifacts which shouldn’t be placed under version control.

The typical Cordova CLI project has at a minimum these directories in the project.

  • www: where your html, css and javascript live
  • merges: platforms specific html, css, javascript
  • .cordova: ‘under the hood’ cordova files and directories, and lifecycle hook scripts
  • platforms: platform specific build directories
  • plugins: downloadable plugins

Based on this Stack Overflow question (which I asked), as well as my experience, the first three directories above should be versioned, and the latter two added to your version control system’s ignore file.

You can, of course, add additional top level directories, and as we continue to explore Cordova CLI, I will show you the directories I have found useful in my development. I don’t think it really matters much which version control system you use–just use one!

In the next post, I will discuss upgrading Cordova CLI, one of the great reasons to keep these directories under version control.

Subscribe to my infrequent Cordova newsletter

Installing And Using Cordova CLI

This will be a short post as Kerri Shots has written up fantastic instructions for installing Cordova CLI. You’ll want to read them carefully. These instructions are a tad out of date, and describe installing the tool on MacOS. I was able to use these as a guide and get Cordova CLI running on Linux (specifically CentOS 6.4), but had to make some modifications (mostly just to get the android SDK running on my version of Linux).

There is also a good doc explaining installation and usage of Cordova CLI in the Github repository.

I also tried installing Cordova CLI on Windows 7. I was using cygwin, but wasn’t able to get the emulator started, and just decided to go with Linux in VirtualBox. Apparently there is an open bug about installing Cordova CLI on Windows 7. For what it is worth, Kerri was skeptical about installing Cordova CLI on any Windows as well.

That said, I know that Cordova supports Windows Phone development (which requires Windows), so I imagine that if this isn’t fixed, it will be soon. If you know any resources for installing Cordova CLI on Windows, please let me know or add a comment.

In the next post I’ll discuss version control.

Subscribe to my infrequent Cordova newsletter

Alternatives to Cordova CLI

If you are interested in building Cordova applications, Cordova CLI has few competitors. The ones I know about:

  • Homegrown script: I built an ant script to do much of what Cordova CLI does–build packages, run tests, and start emulators. I’m sure you could use any other build tool to do the same. There’s some reverse engineering, and tangling with iOS build tools isn’t much fun.
  • Different code trees: use the Cordova create script to create a project for each platform, and then let the html, css, and javascript evolve differently for each, possibly relying on an IDE to do compilation/building. This may be a viable option if you have hard requirements that each platform’s build can be tested against, or if you don’t care to share code between platforms. Upgrading versions of Cordova may be an issue.

As you can see, there aren’t too many other options for doing Cordova development. If you are interested in forward compatibility, I suspect you’ll choose one of the scripting options (Cordova CLI or a homegrown script); if you just want to get the project done, I think you’d lean towards using an IDE after the project is created–it all depends on how future proof you want the app you are building to be.

In the next post, I will discuss installing Cordova CLI.

Subscribe to my infrequent Cordova newsletter

What is Cordova CLI?

I’m planning to write a number of posts documenting my adventures through the new Cordova (aka Phonegap, though there are differences) command line interface, known as Cordova CLI. I am in the midst of working on a Cordova application and have been using Cordova CLI heavily for a while now. My focus has been on the Android platform, though we plan to release to iOS as well, so that will be where the majority, if not all, of my examples are.

These posts only cover cordova cli 2.9. Cordova 3.0 is an overhaul that changes how the core Cordova app is assembled, and therefore has different constraints.

Here’s a list of what I plan to cover:

  • What is Cordova CLI
  • Alternatives to Cordova CLI
  • Installing And Using Cordova CLI
  • Placing Cordova CLI projects under version control
  • Upgrading projects managed with Cordova CLI
  • Hooks and Cordova CLI
  • Configuration management using Cordova CLI
  • Setting up CORS
  • Platform Specific CSS/Javascript with Cordova CLI
  • Platform specific configuration files with Cordova CLI
  • How to set up a new plugin for use with Cordova CLI
  • How to ‘plugman’ify an existing plugin
  • Releasing with Cordova CLI

Cordova CLI is different than the create scripts that have been part of Cordova/Phonegap (hereafter called Cordova for brevity) for a while (though it does use those create scripts). The create scripts only helped you create the project; afterwards you were on your own. Cordova CLI helps you create a project, manage css and javascript resources that differ per platform, develop and test it using both emulators and an in-browser emulator called ‘ripple’, manage plugin dependencies, and build packaged apps suitable for installation on phones and emulators during development. It is a nodejs application that runs on MacOS, Linux, and possibly Windows (see this bug).

Cordova CLI lets you keep the shared html, css, and javascript code in one place, and deploy it to multiple platforms. This is one of the main strengths of Cordova development–one set of logic deployed to multiple mobile platforms.

Be aware that Cordova CLI is early beta software. This is bad because you’ll run into issues; this is good because the software is under active development, and I’ve found the developers to be quite responsive to bug reports. I have occasionally filed a bug one day, and had a fix to download the next.

There are also areas where Cordova CLI has significant deficiencies–luckily they’ve built the software to be flexible enough you can work around it (or, if you can contribute fixes, they are happy to accept help). So, if you plan to use Cordova CLI, make sure you bookmark the issue tracker. Consider joining that jira and submitting bugs, but at the least search it when you run into an issue.

In the next post, I’ll discuss alternatives to Cordova CLI.

Subscribe to my infrequent Cordova newsletter

A Tale of Two Mobile App Development Program Applications

I just can’t believe the difference in the application process between Google (for Google Play) and Apple (for the App Store).

For Google, I had to

  • sign in to a Google account
  • give them an email address and a phone number
  • agree to terms and conditions
  • pay $25 (but make sure you have a valid Google Wallet account!)
  • wait for the registration to be processed
  • invite other developers in my company

For Apple (where I need to register as a corporation) I had to

  • Upgrade a mac to Lion
  • Start the signup process
  • Realize that the company doesn’t have an updated Dun and Bradstreet profile
  • Call Dun and Bradstreet
  • Be sent to http://iupdate.dnb.com/ to update the profile
  • Find out who the executive officers of the company were
  • Get them to sign up to update the profile
  • Update the profile
  • Submit it
  • Wait for over 5 business days
  • Resubmit my application to Apple
  • Get rejected again because they didn’t recognize the company as a legal entity
  • Exchange a couple of emails with Apple employees
  • Determine what the rejection is possibly because I didn’t want for D&B to update the Apple database (up to 14 business days!)

And all that is before I can see (and agree to) the terms of use and pay the $99/year, and get my application processed.

Whew.