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
Sample files
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.
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
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.
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
When
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
The Native class
To create the native code layer, start by creating a new Java class that extends theorg.apache.cordova.api.Plugin
class from the core Cordova API. In Eclipse, go to File->New->Class.
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.
The
When the
Once you have created your native Java class that extends
Below you can see the
Note: Don’t forget to include the Java class
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
Next, after checking the native action, the
When you return a result value for the execute method, you must return an instance of
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.
- 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>
- Also after the
onDeviceReady()
function, add the JavaScript for invoking the native plugin and handling the plugin results. Add JavaScript functions namedcallNativePlugin
,nativePluginResultHandler
,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 );
}
- The
callNativePlugin
function simply calls the JavaScript interface of the native plugin class. When it invokes thecallNativeFunction
method, it passes the callback functions for success and error status received from the native code layer. ThenativePluginResultHandler
function is invoked if there is a success callback from the native layer, and thenativePluginErrorHandler
function is invoked upon an error callback from the native layer.
- 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
When you click the second button, 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
In Eclipse, open the file res/xml/plugins.xml in a text editor view. Next, you need too append a new
The "name" attribute is the value that the
In the new
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.
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".
To launch the application right-click on the Eclipse project, then select "Run As->Android 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.
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.
Comments
Post a Comment