building native mobile applications using HTML, CSS and JavaScript” • Write your applications in HTML, JavaScript, and CSS, and leverage native device services and code via a plugin API. • http://cordova.apache.org
“Nitobi” with the name “PhoneGap” • Adobe acquired Nitobi, and the project was open- sourced and contributed to the Apache Software Foundation under the name “Apache Callback,” which was later changed to “Apache Cordova.” • Adobe now distributes a version of Apache Cordova under the name “PhoneGap,” and offers some additional related services (PhoneGap Build), but the underlying code is Apache Cordova. • http://phonegap.com/
install -g cordova • The cordova package gives you the “cordova” command, which is used for creating projects, building, running, etc. • Older versions of Cordova had different setup routines - see documentation for details. • You can also set it up manual
HelloWorld # hello = folder name (will be created at cwd) # com.example.hello = reverse DNS-style identifier # HelloWorld = app name ! # get into the project folder cd hello ! # add the desired platforms (for cross-platform app creation) cordova platform add ios # requires Xcode/etc. cordova platform add android # requires Android SDK/etc. ! # build the project cordova build ! # test the apps cordova emulate ios # run the app in iOS simulator cordova emulate android # run in Android emulator
Most plugins are invoked via custom objects added to the window.navigator object, but others are event-based, or use other mechanisms. JavaScript code: ! navigator.camera.getPicture( function(result) { /* do something */ }, function(error) { /* do something with error */ }, { /* options */ });
“service” = the name of the native component (e.g. class) “action” = the name of the method to invoke [“firstArgument”, …] = array of arguments to pass to plugin (can be nested arrays, object, primitives, etc.)
from “CDVPlugin” • Implement methods that return (void) and take an argument of (CDVInvokedUrlCommand *) • - (void)myPluginMethod:(CDVInvokedUrlCommand *)command; • Access plugin arguments via command.arguments • JS “primitives” are converted to equivalent native data types (JS string -> NSNumber, etc.) • JavaScript array <-> NSArray/etc. • JavaScript object -> NSDictionary/etc.
“CordovaPlugin” • @Override the “execute” method to invoke plugin methods • @Override public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException • The action parameter is the “action” string passed from the JS code - use this to call a specific method (or just handle the call directly if your class only has one method) • The “execute” method should return true if you have a method for the action, or false if not. Errors should be propagated via the callbackContext, not the return value for execute.
use AJAX in the web app - proxy the call through the native code) • Native data storage (access a client database via native code, using a JS plugin API) • Encryption (slow, difficult in JavaScript) • Custom business logic/algorithms • Offline app use (data storage, store-and-forward)
in the Cordova “config.xml” • Always put a try/catch at the top-level of your plugin method. An unhandled exception in your plugin method may crash or hang the app. • Do not swallow native exceptions - always propagate the error back to the JS code via the callback context “send error plugin result”. Let the JS code decide what to do with errors, not the native code. • If you see try/catch with an “e.printStackTrace()” in your Android code, you’ve got a problem. • The Cordova plugin API allows you to pass an array of items as a plugin argument. Avoid passing bare primitives as plugin arguments and results, unless that’s all you’ll ever need. Rather than passing an array of primitives, pass a single object argument, with keyed arguments. It makes the code easier to write and maintain on the native side, and allows your plugin to be modified/ extended more easily. • Not this: [“my first arg”, 2, false, “another arg”] • This: [{ message: “my first arg”, count: 2, isSpecial: false, errorMessage: “another” }]
each plugin method should only do one thing. Build a collection of plugins that can be combined via JavaScript to accomplish a bigger task. • Keep the application logic in JavaScript, not native code. • Put cordova.exec behind a layer of abstraction, with a stub implementation (or equivalent implementation) for running outside of Cordova land. (In other words, don’t call cordova.exec directly from your code, hide it). • Change the callback.exec callback API into a promise-based API (resolve a promise in the success callback, reject it in the failure callback). Avoid the callback “Pyramid of Doom!”
for issues introduced in newer devices/OS releases. • Cordova app upgrades not always trivial (Cordova 2->3 upgrade more painful) • Device differences, quirks, browser feature support • Browser churn, regressions, missing/buggy/incomplete HTML5 support, etc. (see: Android) • The UX for Cordova apps is sometimes not as smooth and seamless as native apps (gestures, button hitboxes, etc.) • However, Cordova apps are basically cross-platform (assuming the necessary plugins exist on all platforms)