How to add an Android native plugin to a cordova project

Motivation

I have been developing a very simple music player application for Android using Apache Cordova and jQuery Mobile *1 to learn how to develop a hybrid application. But I think the new version of Apache Cordova, I am using version 3.0.4, has been changed significantly and I could not add my own java plugin to my cordova project at first. It took much time for me to solve the problem, so let me share the know-how.

Prerequisites

You need to be able to create a cordova or phonegap project using CLI (Command Line Interface) like below.


% cordova create test com.yohpapa.research.test test
% cd test
% ls
merges/ platforms/ plugins/ www/
% cordova platform add android
% cd platform/android
% ls
AndroidManifest.xml bin/ libs/ project.properties
ant.properties build.xml local.properties res/
assets/ cordova/ proguard-project.txt src/

Of course you also need to be able to build it using Eclipse with ADT plugin or Android Studio (I love it!) When specifying the directory to open it as an Android project with an IDE, you need to set /platforms/android to the project's root directory.

Create native java plugins

You can create native java plugins for your cordova project anywhere under $PROJECT/src as an Android Service class, a POJO class and whatever you like. However, you need to create wrapper classes to execute APIs which these classes expose from javascript. The wrapper classes have to been extended from CordovaPlugin class like below.

public class MyOwnPlugin extends CordovaPlugin {
    @Override
    public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {

        if("do_something".equals(action)) {
            // do something
        } else if("do_another_thing".equals(action)) {
            // do another thing
        } else if("do_other_things".equals(action)) {
            // do other things
        } else {
            return false;
        }
    }
}

Create javascript plugin modules

You need to create javascript plugin modules to execute native java plugins' APIs. you can create them anywhere under assets/www folder, for example assets/www/plugins/my_own_plugin.js. In the file you need to define a wrapper module like below.

cordova.define('cordova/plugin/my_own_plugin', function(require, exports, module) {
    var exec = require('cordova/exec');

    var MyOwnPlugin = function() {};

    MyOwnPlugin.prototype.doSomething = function(onSuccess, onFailed) {
        exec(onSuccess, onFailed, 'MyOwnPlugin', 'do_something', []);
    }

    MyOwnPlugin.prototype.doAnotherThing = function(parameter, onSuccess, onFailed) {
        exec(onSuccess, onFailed, 'MyOwnPlugin', 'do_another_thing', [parameter]);
    }

    MyOwnPlugin.prototype.doOtherThings = function(param1, param2, onSuccess, onFailed) {
        exec(onSuccess, onFailed, 'MyOwnPlugin', 'do_other_things', [param1, param2]);
    }

    module.exports = new MyOwnPlugin();
});

This is similar to Node.js (Express,) isn't it? ...OK, let's return to our subject.

After creating a javascript plugin module, you need to modify two files, config.xml and cordova_plugins.js. First let me talk about modifying config.xml. You need to add declaration of your plugin module like below.

<?xml version='1.0' encoding='utf-8'?>
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0"
        id="com.yohpapa.research.test"
        version="0.0.1">
    <!-- ... -->

    <feature name="MyOwnPlugin">
        <param name="android-package"
               value="com.yohpapa.research.test.MyOwnPlugin" />
    </feature>

    <!-- ... -->
</widget>

Next you need to add your plugin module to cordova_plugins.js like below.

cordova.define('cordova/plugin_list', function(require, exports, module) {
    module.exports = [
        {"file": "plugins/my_own_plugin.js"}
    ]
};

Last you need to copy config.xml to res/xml/config.xml.

Use your plugin in javascript

OK, it's time to use your own plugin. For example, you can use it like below.

<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript">
var myPlugin = cordova.require('cordova/plugin/my_own_plugin');
myPlugin.doSomething(function() {
    console.log("doSomething has been passed.");
}, function(err) {
    console.log("doSomething has been failed.");
});
</script>

You can use your plugin without including my_own_plugin.js with script tag because cordova reads cordova_plugins.js when starting an application and includes your plugin automatically.