Extending PhoneGap with native plugins for Android

Understanding the PhoneGap native plugin structure

Before you start to write PhoneGap native plugins, it will help to understand how the PhoneGap application container exposes native operating system functionality to JavaScript-based applications.

All Cordova APIs consist of two related parts: a JavaScript-based interface that can be accessed within your applications, and the corresponding native class for performing operations in native code. Typically, the JavaScript classes and the native classes have APIs that mirrors each other, so that they are easy to follow. The JavaScript class invokes the native code using the Cordova.exec() function. When it invokes Cordova.exec, it can pass in a result handler function, an error handler function, and an array of parameters to be passed into native code, as well as a reference to the native class’s name and native function name. Cordova will manage the JavaScript-to-native communication, and you can focus on building your application.

To learn more about PhoneGap native plugins, take a look at the core API’s source code, available at the Cordova wiki. The entire PhoneGap framework is built upon the same paradigm you’ll find there.

Building your first plugin

To start building your first PhoneGap native plugin, you’ll need to create a new PhoneGap project following the steps outlined in the article Getting started with PhoneGap in Eclipse for Android. I named my project MyFirstPhoneGapNativePlugin.

The JavaScript class

Once you have set up your Hello Eclipse project, you’re ready to create the JavaScript interface for the native plugin. Create a class with functions that mirrors the logic exposed by the native code. Under the www folder, create a JavaScript file named HelloPlugin.js that contains the simple JavaScript class shown below.

var HelloPlugin = {     
callNativeFunction: function (success, fail, resultType) {      
return cordova.exec( success, fail, "com.sandeeplondhe.HelloPlugin", "nativeAction", [resultType]);     } };

The HelloPlugin class has a single function named callNativeFunction, which accepts a success callback function, an error callback function, and a resultType string parameter. The callNativeFunction function wraps the cordova.exec function, which invokes the actual native code. There is no additional JavaScript inside of this class, but you can add JavaScript code here if you need to.

When cordova.exec is invoked, it expects five parameters:

  • a reference to a success callback function (a function that is invoked upon a successful response from the native code layer)
  • an error callback function (a function that is invoked upon an error response from the native layer)
  • a string reference to the native code class (I cover this in more detail below)
  • a string reference to the action that should be invoked
    • This is different  and other platforms. When building for Android, this is a reference to an action, not the name of the function that is invoked.
  • an array of parameters to be passed into the native code

Keep in mind that code execution between the JavaScript and native code layers is not synchronous, so you’ll need to use callback functions and asynchronous coding practices when developing PhoneGap native plugins.

The Native class

To create the native code layer, start by creating a new Java class that extends the org.apache.cordova.api.Plugin class from the core Cordova API. In Eclipse, go to File->New->Class.

pic1

Figure 1. Creating the new file.

Next, follow the steps in the “New Java Class” wizard, and create a class named “HelloPlugin”, which extends the class “org.apache.cordova.api.Plugin”.

pic2

Figure 2: New Java Class in Eclipse.

The org.apache.cordova.api.Plugin class is the parent class that all Cordova classes must extend. Theorg.apache.cordova.api.Plugin class encapsulates all logic necessary for native-JavaScript communication via the PhoneGAP API.

When the cordova.exec JavaScript function is invoked, the “execute” function on the corresponding native Plugin class is invoked. The Android WebView which is used to render HTML content in PhoneGap applications uses the WebView APIto enable communication back and forth between native code and the JavaScript classes.

Once you have created your native Java class that extends org.apache.cordova.api.Plugin, all you need to do is override the “execute” method to begin building native functionality. The parameters of this method is a string “action”,JSONArray array of parameters passed into the native code from JavaScript, and the callbackId, which is the unique reference to the current native method invocation. Regardless of what action parameter is passed into the native class, the “execute” method is always invoked. It is up to you as the developer to evaluate the action passed into the native layer from the JavaScript layer, and respond accordingly.

Below you can see the HelloPlugin class that extends org.apacha.cordova.api.Plugin.

Note: Don’t forget to include the Java class com.android.Log, otherwise you will get a compiler error in your Eclipse project.

public class HelloPlugin extends Plugin {

public static final String NATIVE_ACTION_STRING=”nativeAction”;

public static final String SUCCESS_PARAMETER=”success”;

@Override

public PluginResult execute(String action, JSONArray data, String callbackId) {

Log.d(“HelloPlugin”, “Hello, this is a native function called from PhoneGap/Cordova!”);

//only perform the action if it is the one that should be invoked              if (NATIVE_ACTION_STRING.equals(action)) {

String resultType = null;

try {

resultType = data.getString(0);

}

catch (Exception ex) {

Log.d(“HelloPlugin”, ex.toString());

}

if (resultType.equals(SUCCESS_PARAMETER)) {

return new PluginResult(PluginResult.Status.OK, “Yay, Success!!!”);

}

else {

return new PluginResult(PluginResult.Status.ERROR, “Oops, Error :(“);

}

}

return null;

} }

For our HelloPlugin class, I have extended the execute method, and the first thing that it does is write a debug message so that you can see that the native code has, in fact, been executed. Next the plugin code checks for the action “nativeAction” which you can see in the NATIVE_ACTION_STRING above. The native code only responds if the action parameter’s value actually matches the “nativeAction” value. This technique is used to prevent misuse of the native code and while this example is basic, the technique should be used in real-world scenarios. You also need to use this technique if you have more than one action possible by a single Plugin class.

Next, after checking the native action, the resultType string is evaluated from the JSONArray, and an appropriatePluginResult response is returned. If the resultType parameter is “success”, a native PluginResult class instance is returned, with the status PluginResult.Status.OK. For any other value, it returns a PluginResult with the status PluginResult.Status.Error.

When you return a result value for the execute method, you must return an instance oforg.apache.cordova.api.NativePlugin. The status and message values returned through the NativePlugininstance is evaluated and used to invoke the appropriate success/error callback handlers from the JavaScript code that invoked the native functionality.

Invoking the plugin

Now that you have created a plugin, you can invoke it from within your PhoneGap application.

  1. First, you need to add a reference to the new plugin’s JavaScript interface class (HelloPlugin.js). Add a new<script> tag inside of your index.html file:

<script type="text/javascript" charset="utf-8" src="HelloPlugin.js"></script>

  1. Also after the onDeviceReady() function, add the JavaScript for invoking the native plugin and handling the plugin results. Add JavaScript functions named callNativePluginnativePluginResultHandler,andnativePluginErrorHandler as shown below:

function callNativePlugin( returnSuccess ) {

HelloPlugin.callNativeFunction(

nativePluginResultHandler, nativePluginErrorHandler, returnSuccess );

}

function nativePluginResultHandler (result) {

alert(“SUCCESS: \r\n”+result );

}

function nativePluginErrorHandler (error) {

alert(“ERROR: \r\n”+error );

}

  1. The callNativePlugin function simply calls the JavaScript interface of the native plugin class. When it invokes the callNativeFunction method, it passes the callback functions for success and error status received from the native code layer. The nativePluginResultHandler function is invoked if there is a success callback from the native layer, and the nativePluginErrorHandler function is invoked upon an error callback from the native layer.
  1. Next add two JavaScript buttons as shown in the code below to invoke the plugin.
<body onload="onBodyLoad()">      
<h1>Hey, it's Cordova!</h1>      
<button onclick="callNativePlugin('success');">Click to invoke the Native Plugin with an SUCCESS!</button>      
<button onclick="callNativePlugin('error');">Click to invoke the Native Plugin with an ERROR!</button>
</body>

When clicked, the first button invokes the callNativeFunction method with the parameter “success”. PhoneGap then executes native code and invoke a success callback in the JavaScript layer (it invokesthenativePluginResultHandler function).

When you click the second button, the callNativeFunction method with is called with the parameter “error”. PhoneGap executes native code and invoke an error callback in the JavaScript layer (it invokesthenativePluginErrorHandler function).

Mapping the native code class

At this point you have almost everything wired up and ready to go, but there is still one more step that you have to complete before you are able to invoke native code from JavaScript.

You have to add a mapping so that Cordova can identify your native code class. Remember the string reference that you used to identify the native class when calling cordova.exec? You need to map that string to the actual class instance in the res/xml/plugins.xml file within your Eclipse project. The res/xml/plugins.xml file contains all configuration information for cordova native APIs available to JavaScript.

In Eclipse, open the file res/xml/plugins.xml in a text editor view. Next, you need too append a new <plugin> XML node entry for the new native plugin that has been created. The <plugin> XML node requires two attributes: name andvalue.

The “name” attribute is the value that the cordova.exec JavaScript function uses to identify the native code. The “name” attribute is used to map to the native class identified by the “value” attribute. If you examine the plugins.xml file, you see that the name “Geolocation”, which is used by the PhoneGap JavaScript API actually corresponds to the native class org.apacha.cordova.GeoBroker.

In the new <plugin> xml node, specify the name “com.sandeeplondhe.HelloPlugin” and the value “com.sandeeplondhe.HelloPlugin” (see Figure 3), and be sure to replace com.sandeeplondhe with your own company identifier. This is the string reference that was used to identify the native class in the third parameter when calling cordova.exec, and it maps to the com.sandeeplondhe.HelloPlugin native class when invoked.

pic3

Figure 3. Editing plugins.xml.

Now you are ready to launch the application and test everything out.

pic4

Figure 4. Debug application.

Once the application launches in the Android Emulator (or on a connected device), you see a simple interface with two buttons (see Figure 5). Click on either button to invoke the native plugin’s native code, and an alert message is displayed via JavaScript upon either a success or error callback.

To launch the application right-click on the Eclipse project, then select “Run As->Android Application”.

pic5

Figure 5. The application running in the Android emulator.

When the native code is invoked, you are also able to see output in the Android debug LogCat window, which reflects the output from the native plugin’s Log.d method invocations (see Figure 6).

pic6

Figure 6. Logged information in the Android LogCat debug console.

Where to go from here

You now know how to start creating native plugins for PhoneGap applications on Android devices. You can use this technique to access Android frameworks that are not exposed by the core PhoneGap SDK, including (but not limited to)android.net, android.bluetooth, and all of the Android APIs exposed via the Android Development Kit. Also, don’t forget to check out the many existing PhoneGap native plugins on GitHub that have been developed by the open source community.

Click on this image to download the Full Source Code:

z

Happy Coding..!

One thought on “Extending PhoneGap with native plugins for Android

Leave a comment