So you are busily
beavering away on your mobile app using
PhoneGap. Unfortunately, you've run into a roadblock as you want to do something that the OS will allow you to do but PhoneGap does not provide and API for it.
Pop quiz hotshot. What do you do? WHAT DO YOU DO? Well obviously the answer is to write a plugin. I mean, the answer is right there in the title of the post. If you didn't figure it out yourself, then I fear for you.
Well let's get into writing a plugin. Before jumping in writing code we need to have some idea of what our requirements are. Hmmm...let's think of something that will be easy but still require the native side to return success or failure to the JavaScript side. I know, let's get the IP address of our device. If we have an IP address our success callback should be executed with the string value that represents the IP address. If we don't have an IP address the error callback should be executed. Sound good? Great, let's dig in.
First, let's think of our JavaScript code and let's write it the fancy new way that uses the PhoneGap version of define and require. Here read the whole thing then I'll explain it more after the break:
The first thing you will notice is that whole thing is wrapped with a call to
cordova.define(). The first argument to define is
id of your plugin and the second is the factory method that creates your plugin.
Next you'll see the curious line:
var exec = require("cordova/exec");
What is happening here is that we are using the require function to define a local variable called
exec, pulling it from the
"cordova/exec" id. This is really important as the
exec method is the magic part of PhoneGap. It's the bit that handles the communication between the JavaScript and native layer. This really is the value add of PhoneGap as we've already found all the bugs that someone starting from scratch would run into.
The next bits are where we declare our constructors for
IPAddress and
IPAddressError. You really don't need to define the
IPAddressError object for this short example but it is a good practice to get into. Actually in this example I won't even return an
IPAddressError object from the native side as I'll leave that as an exercise for the readers. First person to post a solution wins a cookie.
Okay, our
IPAddress object will provide one method called get which will, drumroll please, get the IP Address of your device. Again nothing magical here other than the call to
exec. The method signature of
exec is as follows:
success - your success callback
fail - your error callback
service - your Plugin service name. You'll need this later.
method - the native method to be called
params - a JSON Array of parameters that you can pass to the native side
Finally the last interesting bit is where we create our ipAddress object and export it using
modules.export.
Alright so now we have our JavaScript code done so let's do some Java:
Beautiful eh? Well maybe not. Anyway, when writing your Java code you just need to make sure you class extends the
org.apache.cordova.api.Plugin class. The only method you need to implement is the
exec method. In exec you check to see what action has been called and they execute the proper native code to fullfil the request. If the action does not match anything you have implemented then you want to return a
PluginResult with a status of invalid action. This will let the caller know they are attempt to execute a method that is not implemented.
In our example we only have one action,
"get". If the
"get" method has been requested we will call the
getIpAddress method to retrieve the device's IP address. The implementation details are not important you can see them yourself. What is important is if we get a
null or zero length string we will return a
PluginResult with a status of error. This will cause the error callback of our JavaScript code to be executed. If we do have and IP address we will return a
PluginResult with a status of success and we'll also return the IP address. This will cause our JavaScript success callback to be executed with the ip address as the only parameter to the function.
So all the code is done so we are ready to call our plugin from our app right? Well not quite there is one more step. You need to add a plugin line to your
res/xml/config.xml file. The line follows the format:
<plugin name="service_name" value="full_name_including_namespace"/>
It is important that the
service_name matches the service name you provide as part of the exec command. The
full_name_including_namespace must be the full package and class name of our Plugin. In our specific case it would be:
<plugin name="ipAddress" value="org.apache.cordova.plugins.IPAddressPlugin"/>
Now let's look at the HTML code of our example. It will create and call get on our IP address plugin.
Again, there are a few steps to follow before you use your plugin.
- Register an onload event handler.
- In your onload event handler register an event handler for the deviceready event.
- In your deviceready event handler you are ready to begin calling PhoneGap method.
- Create and ipAddress using cordova.require("cordova/plugin/ipaddress"). The string passed to require must match the one you provided in the earlier cordova.define() method.
- Call the get method on your ipAddress object.
So, that's it. You've built a working plugin from the ground up and it will even get your devices IP address.