Blog

Developing a Cordova (PhoneGap) Plugin for Android

At Plot we received a request to make our library for location based notifications available as a plugin for Cordova/PhoneGap. We looked into this and decided to start with a minimal implementation that would provide the basic functionality to apps created in Cordova/PhoneGap. This article shows how we did this for Android!


Don’t want to think about this? Get started with geofencing without a hassle!

Click Me


If you only want to read how to use the plugin, you can skip to Using the plugin. There will be a separate article describing how we made it work on iOS. Please note that the Cordova/PhoneGap plugin is written for version 3.0.0 and is available under an open source license on GitHub.

About Cordova/PhoneGap

Apache Cordova and Adobe PhoneGap provide a way for developers to develop apps for all major platforms in HTML, CSS and JavaScript. Developers only have to maintain a single codebase for all platforms. The project started out as PhoneGap and when it was acquired by Adobe the code was released as Apache Cordova. Currently the only difference between Apache Cordova and Adobe PhoneGap is the name. Native libraries (such as our Plot library) can be used by writing a plugin which exposes it to JavaScript.

Creating the plugin

The first step in creating the plugin is writing the JavaScript interface. You can map each library call to JavaScript by creating functions like this:

cordova.exec(successCallback, failureCallback, class, method, [arguments]);

As you can see you can specify callbacks that will be executed when the call to your native library has completed. For library calls that do not return anything, you can choose not to expose the success and failure callbacks to the user. We expose the callbacks so that even when the library call does not return anything the app developer knows whether the call has completed successfully.

The final interface is exported as “cordova/plugin/plot” and looks like this:

cordova.define("cordova/plugin/plot", function(require, exports, module) {
	plot = {};
	plot.exampleConfiguration = { "publicKey": "", "cooldownPeriod": -1, "enableOnFirstRun": true, "enableBackgroundModeWarning": true };
	plot.init = function(configuration, successCallback, failureCallback) {
		 cordova.exec(successCallback, failureCallback, "PlotCordovaPlugin", "initPlot", [configuration]);
	};
	plot.enable = function(successCallback, failureCallback) {
		 cordova.exec(successCallback, failureCallback, "PlotCordovaPlugin", "enable", []);
	};
	plot.disable = function(successCallback, failureCallback) {
		 cordova.exec(successCallback, failureCallback, "PlotCordovaPlugin", "disable", []);
	};
	plot.isEnabled = function(successCallback, failureCallback) {
		 cordova.exec(successCallback, failureCallback, "PlotCordovaPlugin", "isEnabled", []);
	};
	plot.setCooldownPeriod = function(cooldownSeconds, successCallback, failureCallback) {
		 cordova.exec(successCallback, failureCallback, "PlotCordovaPlugin", "setCooldownPeriod", [cooldownSeconds]);
	};
	plot.setEnableBackgroundModeWarning = function(enableWarning, successCallback, failureCallback) {
		 cordova.exec(successCallback, failureCallback, "PlotCordovaPlugin", "setEnableBackgroundModeWarning", [enableWarning]);
	};
	plot.getVersion = function(successCallback, failureCallback) {
		 cordova.exec(successCallback, failureCallback, "PlotCordovaPlugin", "getVersion", []);
	};
	module.exports = plot;
});

Next is the native (Android) part of the plugin. That part is responsible for calling your native library and piping the results back to JavaScript. The entry point for your plugin is the execute method. There you determine which command should be executed. Successful calls should result in callbackContext.success() and unsuccessful calls should result in callbackContext.error(). For our library this means that each library call is surrounded by a try-catch block which calls callbackContext.error() on an exception.

Please note that the native code will run on the same thread as the JavaScript. If you are performing CPU intensive or blocking operations it is important to run these on a separate thread. Also native UI operations should be performed on the UI thread. See the PhoneGap Android Development Guide for examples.

The last step is writing a plugin.xml file so that it can be used in the Cordova/PhoneGap CLI tool. In plugin.xml is defined per platform which files have to be copied and what configuration files have to be updated.

We added the our code to a js-module which is added to plugin.xml using this snippet:

<js-module src="plot.js" name="Plot">
    <clobbers target="plot" />
</js-module>

In case of our plugin one java source file has to be copied, one library file has to be copied and two sections of AndroidManifest.xml have to be changed. The files are copied with these two lines:

<source-file src="src/android/plot_v_1_4_2.jar" target-dir="libs" framework="true" />
<source-file src="src/android/PlotCordovaPlugin.java" target-dir="src/com/plotprojects/cordova" />

The configuration changes, adding the required permissions and adding new receivers/services is done with:

    
        
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            <category android:name="android.intent.category.HOME" />
        
    

    
        
            <action android:name="$PACKAGE_NAME.plot.OpenNotification" />
        
    

    <service android:name="com.plotprojects.retail.android.PlotBackgroundService"
             android:process=":PlotProcess">
        <meta-data android:name="debug" android:value="false" />
    </service>

The permissions are added by the following lines:

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.VIBRATE"/>

PhoneGap adds the INTERNET permission by itself, therefore it isn’t required to add permission again here.

You can see the complete source on GitHub: https://github.com/Plotprojects/plot-phonegap-plugin

Using the plugin

Starting from version 3.0.0 of Phonegap, it is made much easier to install plugins. You only have to link to where the plugin can be downloaded and Phonegap will install the plugin for you.

You can add Plot to your existing project by running:

phonegap local plugin add https://github.com/Plotprojects/plot-phonegap-plugin

and adding the following code to the html page that gets loaded first (often index.html):

<script type="text/javascript">
document.addEventListener("deviceready", deviceReady, true);
function deviceReady() {
    var plot = cordova.require("cordova/plugin/plot");
    var config = plot.exampleConfiguration;
    config.publicKey = "REPLACE_ME"; //put your public key here
    plot.init(config);
}
 </script>

Conclusion

It’s actually quite easy to make your library available to Cordova/PhoneGap users. It only requires a small amount of code to make the plugin. For the end user that will be using the plugin it is really easy with the latest PhoneGap version. Just run one command and add a snippet of code that calls your library, and you’re done.

Resources

PhoneGap Plugin Development Guide
PhoneGap Plugin (XML) Specification
PhoneGap Android Plugin
Plot Library documentation


Don’t want to think about this? Get started with geofencing without a hassle!

Click Me

Spread the love