PhoneGap with native plugins for Android

Requirements

Prerequisite knowledge

A good understanding of the fundamentals of PhoneGap and programming in Objective-C is required to make the most of this article.

User level

Intermediate
This article examines native plugins for PhoneGap (also known as Apache Cordova) applications in Eclipse, targeting Android devices. If you are just starting out with PhoneGap or if you need to review the fundamentals of PhoneGap, read Getting started with PhoneGap in Eclipse for Android before continuing.
The terms Cordova and PhoneGap are used interchangeably within this article to refer to the same open source application platform that lets you create natively-installed mobile applications using HTML and JavaScript. The PhoneGap codebase moved to open source at Apache Software Foundation under the name Cordova. Adobe is still distributing it under the name PhoneGap. For more information, check out Brian Leroux's blog post "PhoneGap, Cordova, and what's in a name?" As Brian says in the post, "Currently, the only difference is in the name of the download package and will remain so for some time."
Not only does PhoneGap enable you to build user interfaces for natively installed mobile applications using web technologies, PhoneGap also provides a JavaScript-based API to interact with native device functionality. By default, PhoneGap provides access to the device camera, accelerometer, file system, GPS location, and media playback among other capabilities. However, PhoneGap does not expose every native API for use within your JavaScript applications. If you want PhoneGap to do more than its default feature set, you can use the PhoneGap native plugin model to extend the capabilities of the core PhoneGap API.
Native plugins in PhoneGap are not like plugins in desktop browsers; rather they provide a way for you to plug in custom code to add to what the PhoneGap application framework can do. PhoneGap native plugins enable you to create completely new, custom functionality in native code, and expose that to your PhoneGap applications via PhoneGap's native-to-JavaScript bridge. This means that you can expose any native library or framework for use within your JavaScript-based PhoneGap applications.

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.tricedesigns.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 from iOS 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.
Figure 1. Creating the new file.
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".
Figure 2: New Java Class in Eclipse.
Figure 2: New Java Class in Eclipse.
The org.apache.cordova.api.Plugin class is the parent class that all Cordova classes must extend. The org.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 API to 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 appropriate PluginResult 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 of org.apache.cordova.api.NativePlugin. The status and message values returned through the NativePlugin instance 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 invokes thenativePluginResultHandler 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 invokes thenativePluginErrorHandler 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 and value.
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.tricedesigns.HelloPlugin" and the value "com.tricedesigns.HelloPlugin" (see Figure 3), and be sure to replace com.tricedesigns 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.tricedesigns.HelloPlugin native class when invoked.
Figure 3. Editing plugins.xml.
Figure 3. Editing plugins.xml.
Now you are ready to launch the application and test everything out.
To launch the application right-click on the Eclipse project, then select "Run As->Android Application".
Figure 4. Debug application.
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.
Figure 5. The application running in the Android emulator.
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).
Figure 6. Logged information in the Android LogCat debug console.
Figure 6. Logged information in the Android LogCat debug console.

Comments

Popular posts from this blog

How to draw an overlay on a SurfaceView used by Camera on Android?

Create EditText with dropdown in android

Android TCP Connection Chat application