This is where plugins come in. Plugins are a way to interface native code with your hybrid solution, and today we’ll talk about how to make our own.
Here is a github project containing the working examples in this post.
You need three things to make a Cordova Plugin:
- A plugin.xml file
- A Java class extending the
CordovaPluginclass that overrides the
In this post we’ll create the ReversePlugin. This magical plugin will take a string, reverse it using Java and give it back to us. We’ll go over each piece and explain how to set things up and various caveats to watch out for in each step.
First, create a directory to house all your files. You’ll need everything packaged in a directory any way to install the plugin and test it out. In that directory, create a
Here is our example plugin.xml, we’ll go over the included tags.
The root tag is the
<plugin> tag. This includes the XML Namespace (
xmlns) an id and a version attribute. The id and version attributes are what show up when you call
ionic plugin ls in your normal Ionic applications. This tag houses the rest of our tags.
The next few tags are used for various plugin management systems, for example plugman. These tags are
After that we start to get into the meat of things. The
<js-module> tag we see the
<clobbers> tag. The
target attribute in this tag tells the system which variable our interface will take over in the application. In our example, we’ll have an instance of the Reverse object in the
window.reverse property, and it will be available globally.
Finally, we get to the
<platform> tag. Within this tag, you define the specifics for the native platform your plugin supports. By looking at the
name attribute, you can see we’re only supporting the Android platform for this plugin. If we were to support another platform, it would have its own
The guts of our
<platform> tag is very Android specific. The first tag underneath
<platform> is the
<config-file> tag. This is a very important tag as it lets you modify the configuration file of your Ionic application when the plugin is installed or updated.
target attribute tells the system which file we’re going to modify, and the
parent attribute sets which XML node we’re going to modify. In the case of our example, we’re after
config.xml in our application and the root node.
<feature> tag inside the
<config-file> tag is the XML we’re going to place in the
config.xml file. The
name attribute of the
<feature> tag is extremely important, as it is the name you’ll use for the
service parameter when calling
<param> tag inside the
<feature> tag explains that our feature is an android package, and the
value attribute is the full namespace, including class name, of our Java class.
<feature> tag but still within the
<platform> tag we have the
<source-file> tag. This tag tells the system where our Java source file exists, and the location it should be put in when compiling our APK. This should be in a reverse domain notation folder structure like all normal Java files.
Step two in the process is building the Java side of the plugin that will handle the native code we care about. Here is the Java file for reversing the string.
Lets start with the very first line.
package com.sciencevikinglabs.reverseplugin; is setting the namespace of our file. This, along with the name of our class is used in the
value attribute of the
<param> tag inside the
<feature> tag of our
After the imports we see the class declaration. You can name your class whatever you want, but it must extend
CordovaPlugin or it won’t be picked up by the system.
Inside the class we see a standard Java constructor, then an
initialize function. This function is fired right before the plugin comes into use for the first time. If you want this function to be fired immediately as your application starts loading, add
<param name="onload" value="true"/> to the
<feature> tag of your
The final function we see is the
execute function. This function is responsible for responding to the
action parameter is the action taken by the user, and
args is an array of arguments passed to the action.
This function should do whatever the action is responsible for, call the
true to tell Cordova that everything worked.
If an error occurs, you can call the
callbackContext.error function with a
false so that Cordova knows there was an issue with that action.
clobbers tag of your
The first thing we do is
require('cordova'). This lets us fire the
exec function that will find our Java code and run it for us.
Next we create a Reverse class that will basically be a wrapper for the
exec call. As you can see from the above example, we created a terrible function name and used it to fire
There are a couple gotchas regarding the
cordova.exec call that I have noticed. The first is that if you don’t pass some kind of function to the success and failed callback parameters, the call just silently fails. That is the reason for checking if those callbacks are null and replacing them with a blank function if they are.
The second gotcha has to do with the third parameter passed to
cordova.exec. The string you pass here has to be the same string as the
name attribute of the
<feature> tag inside your
Now, the fourth parameter is the action that will be passed as the action string in the Java class. The final parameter has to be an array. This array will be passed as the args JSONArray parameter in the Java class. Use those parameters to pass data into the plugin as needed.
As you can see, writing a plugin can require a few steps and the ride can be very bumpy if you don’t get your configuration just right. I would recommend that you write a Java class outside of the plugin to use inside the plugin as simply as possible so it can be nicely isolated and unit tested. This will make the native code side of the issue much easier.
Also, try to name everything the same. That way you don’t have to remember if you pluralized something, or added some silly prefix or suffix in one spot, but not the other and it results in a broken plugin.
Another useful function the plugin architecture provides is hooks. Hooks let you run a script at specific points of the install, prepare or build processes. There is a bit to go over there so we’ll cover it in another post.
Although there are a few things that can be done to make the plugin writing process simpler, it’s a very powerful tool that lets you interact with native code and Cordova did a fine job in implementing such a useful feature.