A lot of exciting things have happened in the past six months or so: my former employer
Nitobi got acquired by
Adobe and our team of about 18 more or less got split right down the middle. Half are now settling into San Francisco, while the rest (me included) are holding down the Canadian fort in Vancouver and doing our best to represent
Adobe up in the Great White North.
I’m still working on
PhoneGap, now reborn as an
Apache Software Foundation project known as
Cordova. My most recent task has involved bringing the disparate implementations of
Cordova‘s
JavaScript API – a consistent, cross-platform API – under one repository. Up until this point, each platform maintained its own set of JavaScript files implementing this API. The idea and implementation I’m going to present in this post is that 90+ percent of the JavaScript for any given
Cordova platform is identical. Most of the
Cordova API boils down to sending simple messages to the native framework, with the expectation that a failure or success callback will be fired in the future back in
Cordova‘s web context. The unified JavaScript project is called
cordova-js.
I’m excited to say that in
Cordova 1.5 we landed
cordova-js in the
Android implementation. In
Cordova 1.6 we are going to drop it into the
iOS implementation! It has already landed in the Apache
Cordova iOS master!
The project has been an up-and-down ride.
Dave Johnson and
Michael Brooks of
Nitobi initially championed this idea with the
phonegap-js project. Months later,
Gord Tanner from
RIM (along some
daleks) was using the same direction
phonegap-js laid down to integrate new APIs in their open source device and API emulation tool,
Ripple.
Gord and company (mostly the old
TinyHippos crew, which got acquired by
RIM) reached out to us to show us what they did. What we saw blew our minds: clean, modular syntax for all API definitions with a very clear architecture and obvious mappings to JavaScript properties and globals. Around this time I jumped in to help out where I could and
Gord,
Ken Wallis and
Laurent Hasson from
RIM all flew up to Vancouver so that we could discuss the
cordova-js implementation and hack on it for a few days (and maybe drink a few beers while we’re at it). Turned out to be a very fruitful week with lots of progress made. One of the early contention points of the project was: how are we going to implement the module system? Should we use an existing solution out there or roll our own? Luckily for us peeps in Vancouver,
Mozilla has an
office and a team up here, and among the talented people working there is
James Burke, author of
require.js. Who better to talk to about the situation than a man closely involved and directly influencing the various styles of JavaScript modules floating around? We ran a little lunch-n-learn and invited
James over to come share ideas. Initially we ended up using
almond.js, a small module loader that was compatible with both
AMD and
CommonJS modules. Later on, to enforce our own requirements (specifically around throwing exceptions for non-existent modules), we forked and cut down
almond.js to the bare-bones that we need for
cordova-js purposes. Finally we were on track to ship a working version of
cordova-js. Android was our first target.
Joe Bowser (of
Adobe/
Nitobi) and
Simon MacDonald (of
IBM) helped make that happen.
Becky Gibson (of
IBM) and
Shazron Abdullah (
Adobe/
Nitobi) put a lot of work in to get it going on iOS.
Patrick Mueller (
IBM),
Brian LeRoux (
Adobe/
Nitobi) and
Jesse MacFadyen (
Adobe/
Nitobi) chimed in to offer advice and guidance. Truly a team and community effort across corporations (warms my heart!). Thanks to everyone involved for making it happen. This lays down the foundation for us to hit our goals for
Cordova 2.0.
Why?
If it works, why f*** with it? The answer lies in the road ahead to
Cordova 2.0. We want any arbitrary device APIs – be they
Cordova “core” APIs or not - to be installable, discoverable and removable at a developer’s discretion. For those familiar with
PhoneGap plugins, this is exactly the same idea. A stock
Cordova API is no different from a plugin. We’ve been part of the way there for some time now; all of the various native implementations employ some manner of plugin architecture. The JavaScript, however, has been a wild-west of sorts. We are changing that with the introduction of
cordova-js.
The biggest change is the use of modules in JavaScript.
CommonJS-inspired but much simpler, it does the job for now. A
simple define and require syntax is used and scoped only to the cordova.js file. Within the cordova.js file you’ll see things like:
define('cordova/channel', function() { // Amazing code goes here }); // ... somewhere else in the code var channel = require('cordova/channel'); channel.onDeviceReady.fire();
All of the little interesting bits inside the cordova.js file are wrapped in a
define call, turning cordova.js into a set of small, focused modules tasked with doing one thing well. Early on we scoped our module syntax globally.
This turned out to be a bad idea. Now,
define and
require are available inside the cordova.js file, or if you want to use it for your own projects you can access these methods via
cordova.define or
cordova.require.
A side effect of using a
CommonJS-inspired module syntax is that we can use the resulting script file interchangeably between
node and
PhoneGap/
Cordova contexts. Due to our simple module system for use in WebView contexts, we can maintain the convention of one-closure-per-file employed in other
CommonJS environments, or piggy-back off of
node‘s module system to do cool things such as run unit tests locally in
node. Winning!
As for changes introduced with
cordova-js, the main one is the name switch in your JS from
PhoneGap to
cordova.
Next up I’ll be aiming to explain a general process for upgrading pre-1.5 plugins to this new approach (perhaps a case study / real world plugin upgrade to go along with it?).
Happy coding!
[This post was originally posted by
Fil Maj on
filmaj.ca]
No comments:
Post a Comment