View
 

How to Create a PhoneGap Plugin for Android

Page history last edited by Tim Walsh 6 months, 2 weeks ago Saved with comment

 


 

Introduction

 

This is a Step by Step Tutorial for Android PhoneGap Plugin. If you are new to PhoneGap please refer to this documentation. Incase you are new the concept of PhoneGap Plugin, please refer to this documentation.

 

Plugin Idea

 

PhoneGap provides an API to read and write file, however it does not provide a api to list files. We will build a PhoneGap Plugin named DirectoryListingPlugin which helps us read contents of say SDCARD on Android. This is shown in the video below.

 

 

 

Download Source Code

Download the source code of the Tutorial here 

 

Creating PhoneGap Plugin Project

 

Create an Android Project

 

 

 

Include PhoneGap Dependencies

 

Refer to the PhoneGap Getting Started Documentation for this.

 

Implement Plugin Class

 

 

 

Add your implementation to execute method()

Here are the guidelines

 

 

  1. action contains the action sent by the javascript. This can be used to do more than one action when javascript calls this plugin. e.g for File Plugin, the action could be LIST,MKDIR,DELETE, etc
  2. data is the arguments coming from JavaScript API to the native. This is an JSON Object. e.g for File Plugin are filename,path,etc
  3. callbackId - TBD
  4. When Javascript calls the plugin it is a non blocking call. The javascript is notified back using callbacks 

 

Complete Source Code

 

 

/**
 * Example of Android PhoneGap Plugin
 */
package com.trial.phonegap.plugin.directorylisting;
import java.io.File;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
import com.phonegap.api.PluginResult.Status;
/**
 * PhoneGap plugin which can be involved in following manner from javascript
 * <p>
 * result example - {"filename":"/sdcard","isdir":true,"children":[{"filename":"a.txt","isdir":false},{..}]}
 * </p>
 * <pre>
 * {@code
 * successCallback = function(result){
 *     //result is a json
 *  
 * }
 * failureCallback = function(error){
 *     //error is error message
 * }
 *
 * DirectoryListing.list("/sdcard",
 *			  successCallback
 *			  failureCallback);
 *		                               
 * }
 * </pre>
 * @author Rohit Ghatol
 * 
 */
public class DirectoryListPlugin extends Plugin {
/** List Action */
public static final String ACTION="list";
/*
* (non-Javadoc)
* @see com.phonegap.api.Plugin#execute(java.lang.String,
* org.json.JSONArray, java.lang.String)
*/
@Override
public PluginResult execute(String action, JSONArray data, String callbackId) {
Log.d("DirectoryListPlugin", "Plugin Called");
PluginResult result = null;
if (ACTION.equals(action)) {
try {
String fileName = data.getString(0);
JSONObject fileInfo = getDirectoryListing(new File(fileName));
Log.d("DirectoryListPlugin", "Returning "+ fileInfo.toString());
result = new PluginResult(Status.OK, fileInfo);
} catch (JSONException jsonEx) {
Log.d("DirectoryListPlugin", "Got JSON Exception "+ jsonEx.getMessage());
result = new PluginResult(Status.JSON_EXCEPTION);
}
}
else {
result = new PluginResult(Status.INVALID_ACTION);
Log.d("DirectoryListPlugin", "Invalid action : "+action+" passed");
}
return result;
}
/**
* Gets the Directory listing for file, in JSON format
* @param file The file for which we want to do directory listing
* @return JSONObject representation of directory list. 
*  e.g {"filename":"/sdcard","isdir":true,"children":[{"filename":"a.txt","isdir":false},{..}]}
* @throws JSONException
*/
private JSONObject getDirectoryListing(File file) throws JSONException {
JSONObject fileInfo = new JSONObject();
fileInfo.put("filename", file.getName());
fileInfo.put("isdir", file.isDirectory());
if (file.isDirectory()) {
JSONArray children = new JSONArray();
fileInfo.put("children", children);
if (null != file.listFiles()) {
for (File child : file.listFiles()) {
children.put(getDirectoryListing(child));
}
}
}
return fileInfo;
}
}

 

Implement Plugin JavaScript

 

Steps

 

  1. Create a file called directoryListing.js
  2. In it create a class named DirectoryListing 
  3. Create a member function named list().
  4. In list()  function call PhoneGap.exec(<<successCallback>>,<<failureCallback>>,<<Plugin Name>>,<<Action Name>>,<<Arguments Array>>);
  5. Finally register both DirectoryListing class as an JavaScript Plugin and register Java Class as the native Plugin (invoked from javascript)

 

/**
 *  
 * @return Object literal singleton instance of DirectoryListing
 */
var DirectoryListing = function() {
};

/**
  * @param directory The directory for which we want the listing
  * @param successCallback The callback which will be called when directory listing is successful
  * @param failureCallback The callback which will be called when directory listing encouters an error
  */
DirectoryListing.prototype.list = function(directory,successCallback, failureCallback) {
 return PhoneGap.exec(    successCallback,    //Success callback from the plugin
      failureCallback,     //Error callback from the plugin
      'DirectoryListPlugin',  //Tell PhoneGap to run "DirectoryListingPlugin" Plugin
      'list',              //Tell plugin, which action we want to perform
      [directory]);        //Passing list of args to the plugin
};
 
PhoneGap.addConstructor(function() {
                   PhoneGap.addPlugin("directoryListing", new DirectoryListing());
               });

 

 

Note that prior to PhoneGap v1.0.0 the addConstructor function above also needed a line to register the native (java) class with PhoneGap's plugin manager. Hence if you download the sample code you will see this line included in the addConstructor function.

              PluginManager.addService("DirectoryListPlugin","com.trial.phonegap.plugin.directorylisting.DirectoryListPlugin");

          From version 1.0.0 the plugin manager was removed and replaced with the res/xml/plugins.xml file. You need to add the following line to it:

              <plugin name="DirectoryListPlugin" value=""com.trial.phonegap.plugin.directorylisting.DirectoryListPlugin"/>

          If you see a Failed to run constructor: ReferenceError: PluginManager is not defined warning its probably because you are on version 1.0.0 or higher and are still           trying to use addService in your Javascript constructor. 

 

 

Write TestCase for the Plugin

Coming Soon... (I am working on a strategy to use Selenium JavaScript to test phonegap)

 

Test the plugin

 

In order to test the plugin, you need to create a dummy application which consumes the plugin.

 

This can be done by creating a standard PhoneGap application for Android and including either the Java source code for your plugin or the JAR as well as the the JavaScript code.

 

The one thing to do when you are actually including a plugin in an application is that you need to edit the /res/xml/plugins.xml file such that the JavaScript code can get access to the Java plugin code. Add the following XML element as a child of the "plugins" element in the plugins.xml file:

 <plugin name="DirectoryListPlugin" value="com.trial.phonegap.plugin.directorylisting.DirectoryListPlugin" />

 

In our case the resulting application is shown below:

 

 

 

Complete Source Code 

 

<!DOCTYPE HTML>

<html>

     <head>

          <title>PhoneGap</title>

     </head>

     <body>

          <!-- Button -->

          <input disabled id="list-sdcard" type="button" value="List SDCard Contents"  />

          <hr>

 

          <!-- Place Holder for placing the SD Card Listing -->

          <div id="result"></div>

 

          <hr>

 

          <script type="text/javascript" src="phonegap-1.0.0.js"></script>

          <script type="text/javascript" src="directorylisting.js"></script>
          <script type="text/javascript" >

   document.addEventListener('deviceready', function() {

   var btn = document.getElementById("list-sdcard");

   btn.onclick = function() {

    window.plugins.directoryListing.list(    "/sdcard",

function(r){printResult(r)},

function(e){console.log(e)}

);

    }

    btn.disabled=false;

  }, true);

 

 

 function printResult(fileInfo){

  var innerHtmlText=getHtml(fileInfo);    

  document.getElementById("result").innerHTML=innerHtmlText;

 }

 

 function getHtml(fileInfo){

 var htmlText="<ul><li>"+fileInfo.filename;

 if(fileInfo.children){

 

 for(var index=0;index<fileInfo.children.length;index++){

 htmlText=htmlText+getHtml(fileInfo.children[index]);

 }

 }

 htmlText=htmlText+"</li></ul>";

 return htmlText;

 

 } 

          </script>

 

     </body>

</html>

 

Packaging the plugin

 

JAR up your Java source code.

 

Create a ZIP file containing your JAR and JavaScript file.

 

That's it!

 

When people "install" your plugin it will be similar to the process that you used for testing the plugin ... for now!