Creating Cordova/Phonegap plugins

Filipe Ximenes
March 27, 2015
<p>Building hybrid mobile apps is all nice and easy until you need some native feature that does not yet have a cordova package. But don't you worry, we will show you how to do it.<br>We will be writing a plugin to run some simple android code and call it from the javascript side.</p><p>I'll be running Cordova version 4.3, so be aware things might be different for other versions.</p><h2 id="a-native-toast-plugin">A native toast plugin</h2><p>We will be working on a native toast plugin for android devices. This will allow us to walk through most of the basic concepts of plugin development.</p><h2 id="the-plugin-xml-file">The plugin.xml file</h2><p>First, create a new folder to start your plugin development outside from your project.</p><pre><code>mkdir my_alert_plugin </code></pre><p>Now create a file inside it and call it <code>plugin.xml</code>.<br>This file is where you do all the configuration and tell Cordova how to install the plugin. It should be placed at the root of your project.<br>Let's start with a simple configuration:</p><pre><code class="language-xml"> &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="br.com.vinta.cordova.toast" version="0.0.1"&gt; &lt;name&gt;Toast&lt;/name&gt; &lt;description&gt;Cordova native toast pluggin for Android&lt;/description&gt; &lt;license&gt;Apache 2.0&lt;/license&gt; &lt;keywords&gt;cordova,toast&lt;/keywords&gt; &lt;/plugin&gt; </code></pre><p>This is a pretty standard configuration file, all the tags are self explanatory. The only thing you should be be careful is with the <code>plugin:id</code> property. This property should be an string that uniquely identifies your plugin. It's a convention to use the <a href="http://en.wikipedia.org/wiki/Reverse_domain_name_notation">reverse domain name notation</a>.</p><h2 id="the-native-code">The native code</h2><p>Let's now move to create the native code that shows the alert. This will be a standard java file, that has access to all the default Android and Cordova libraries.</p><p>Place the code in <code>src/android/MyToast.java</code><br>This is the basic structure of the Java class:</p><pre><code class="language-java">package br.com.vinta.cordova.toast; import org.apache.cordova.CordovaWebView; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CordovaInterface; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.widget.Toast; public class MyToast extends CordovaPlugin { public MyToast() { } @Override public void initialize(CordovaInterface cordova, CordovaWebView webView) { super.initialize(cordova, webView); } @Override public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { } } </code></pre><p>The <code>initialize</code> method should call it's <code>super</code> and can also be used to do any extra initialization work you need.<br>The <code>execute</code> method is where the magic happens. All javascript calls to your plugin will go through this method and it's its responsibility to route then to run the appropriate code.</p><h2 id="showing-a-toast-message">Showing a toast message</h2><p>Inside the <code>MyToast</code> class we will create the method that shows the alert:</p><pre><code class="language-java">public void showToast(String message, final CallbackContext callbackContext){ Context context = this.cordova.getActivity().getApplicationContext(); Toast toast = Toast.makeText(context, message, Toast.LENGTH_SHORT); toast.show(); callbackContext.success("Nice!"); } </code></pre><p>This is also pretty simple, we are creating a toast and showing it with a given message. In the and we call <code>callbackContext.success</code> to return a message to the javascript code.</p><h2 id="executing-the-the-showtoast-method">Executing the the showToast method</h2><p>As previously said, all native calls are sent to the <code>execute</code> method. We have to manually define how the call will be treated.</p><pre><code class="language-java">@Override public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { if ("showToast".equals(action)) { this.showToast(args.getString(0), callbackContext); }else{ return false; } return true; } </code></pre><p>The <code>action</code> will tell us witch method should run. <code>args</code> will contain arguments passed, in our case, it will contain only one argument with the message to be passed to the <code>showToast</code> method.<br>It's also worth noticing that the execute method should return <code>true</code> in case the requested action was found and <code>false</code> otherwise.</p><h2 id="the-javascript-interface">The javascript interface</h2><p>Almost done! Create a folder named <code>www</code> and a file <code>toast.xml</code>. This is how it will look like:</p><pre><code class="language-javascript">var obj = {}; obj.show = function(message, successCallback, errorCallback) { cordova.exec( successCallback, errorCallback, "MyToast", "showToast", [message]); }; module.exports = obj; </code></pre><p>We defined the <code>show</code> function that receives a message to be shown and callbacks of success and error.<br>The <code>cordova.exec</code> function is responsible to make the bridge from the javascript to the native code. It receives the callbacks, a <code>service</code>, witch in our case is <code>MyToast</code>, an <code>action</code>, and a list of parameters. And that's all we need in the javascript side.</p><h2 id="connecting-everything-in-plugin-xml">Connecting everything in plugin.xml</h2><p>All is left is to teach Cordova how to install the plugin. This is done in the <code>plugin.xml</code>:</p><pre><code class="language-xml"> &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android" id="br.com.vinta.cordova.toast" version="0.0.1"&gt; &lt;name&gt;Toast&lt;/name&gt; &lt;description&gt;Cordova native toast pluggin for Android&lt;/description&gt; &lt;license&gt;Apache 2.0&lt;/license&gt; &lt;keywords&gt;cordova,toast&lt;/keywords&gt; &lt;js-module src="www/toast.js" name="toast"&gt; &lt;clobbers target="toast" /&gt; &lt;/js-module&gt; &lt;!-- android --&gt; &lt;platform name="android"&gt; &lt;config-file target="res/xml/config.xml" parent="/*"&gt; &lt;feature name="MyToast" &gt; &lt;param name="android-package" value="br.com.vinta.cordova.toast.MyToast"/&gt; &lt;/feature&gt; &lt;/config-file&gt; &lt;source-file src="src/android/MyToast.java" target-dir="src/br/com/vinta/cordova/toast"/&gt; &lt;/platform&gt; &lt;/plugin&gt; </code></pre><ul><li><code>js-module</code>: sets the name of your plugin and where the javascript interface is.</li><li><code>clobbers</code>: sets the global variable name used access your plugin.</li><li><code>config-file</code>: <code>target</code> tells where to place the configuration about the feature you are developing.</li><li><code>feature</code>: is the name of the service.</li><li><code>param</code>: tells the package where the service is placed.</li><li><code>source-file</code>: tells where a file should be placed. Is our case, <code>MyToast.java</code> will be placed in the <code>src</code> directory corresponding to its package name.</li></ul><h2 id="testing-our-plugin">Testing our plugin</h2><p>To install our plugin, we will use <code>plugman</code>, install it using:</p><p><code>npm install -g plugman</code></p><p>and run from the root folder of the project you want it to be installed:</p><pre><code>plugman install --platform android --project platforms/android/ --plugin /path/to/plugin/root/folder/ --plugins_dir plugins/ </code></pre><p>now place the code to show the toast in your project:</p><pre><code class="language-javascript">toast.show("It works!!!", successCallback, errorCallback); </code></pre><p>and run from terminal:</p><pre><code>cordova run android </code></pre><p>Great, that's all!<br>Link to full project <a href="https://github.com/vintasoftware/cordova-toast-plugin">here</a>.<br>If you are interested in developing web or mobile apps, send a message about your project to <a>contato@vinta.com.br</a></p>