One big advantage to using the PhoneGap cross-platform framework for developing mobile applications using HTML, CSS, and Javascript is that it is fairly simple to extend the current framework by re-using existing plugins or writing your own plugin. If you want to use an existing plugin, all you have to do is copy the Java and Javascript source code into your project, extend your plugins.xml file, and start using the plugin from inside your existing Javascript. If you wish to create a plugin, it helps to look at an existing plugin before trying to write your own. In a nutshell, your plugin will have a Java file and a Javascript file, which you’ll link in the plugins.xml file.

PhoneGap’s wiki provides great information about how to start writing Plugins. The example in the Android section is a plugin that will allow you to get a list of the files and folders on a phone’s SD card. The information is straight-forward, so I won’t bore you by regurgitating what they have already clearly documented. Instead, I will play Devil’s advocate and look at doing the same task except natively in Android. The point is to compare the amount of code and the relative performance for each approach.

Code comparison

PhoneGap

I started by creating the plugin example in an Android project. When I was finished, I had the following components:

Native:

  • DirectoryListPlugin.java
  • SDList_PGActivity.java
  • plugins.xml
  • phonegap-1.0.0.jar

Web Assets:

  • index.html
  • directorylisting.js
  • phonegap-1.0.0.js

Native

Next, I created a separate Android project and replicated the SD list using native UI elements. The components of this project are:

  • SDListActivity.java
  • main.xml
  • simple_list_item.xml

If we’re judging the code by number of components, the native solution is much more light-weight. But first let’s look at SDListActivity.java in my native solution:

public class SDListActivity extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

}
public void ListButtonClick( View v ) {
try {
long beginTime = new Date().getTime();
ArrayList<String> sdCardList = getDirectoryListing( new File("/sdcard/"), "" );
String[] sdCard = sdCardList.toArray(new String[sdCardList.size()]);
((ListView)findViewById(R.id.SDList)).setAdapter(new ArrayAdapter<String>(this, R.layout.simple_list_item, sdCard));

long endTime = new Date().getTime();

Toast.makeText( this, “Took ” + ((endTime – beginTime)/1000.0) + ” seconds to execute”, Toast.LENGTH_SHORT).show();

}

catch( Exception error ) {

Log.e( “SDListTest”, “ListButtonClick: ” + error.toString() );

}

}

/**
* Gets the Directory listing for file, in JSON format
* @param file The file for which we want to do directory listing
* @return ArrayList<String> representation of directory list.
*  e.g {"filename":"/sdcard","isdir":true,"children":[{"filename":"a.txt","isdir":false},{..}]}
* @throws JSONException
*/
private ArrayList<String> getDirectoryListing(File file, String prefix) throws JSONException {
ArrayList<String> fileInfo = new ArrayList<String>();
try {
fileInfo.add(prefix + file.getName());
if (file.isDirectory()) {
if (null != file.listFiles()) {
for (File child : file.listFiles()) {
fileInfo.addAll(getDirectoryListing(child, prefix + "    "));
}
}
}
}
catch( Exception error ) {
Log.e("SDListTest", "getDirectoryListing: " + error.toString());
}
return fileInfo;

}

}

The getDirectoryListing method is a slightly modified version of the one from the PhoneGap plugin.

The only code left to add is the ListButtonClick method, which calls getDirectoryListing and binds the String array result to a native ListView. If you ignore the code to track the time it takes for this operation to complete, there are only three lines of code inside the method.

The xml files are also pretty basic. “main.xml” contains a Button and a ListView:

<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="List SD Card"

android:onClick="ListButtonClick"

></Button>
<ListView android:id="@+id/SDList"

android:layout_width="fill_parent"

android:layout_height="wrap_content" />
</LinearLayout>

“simple_list_item.xml” is only a single TextView:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@android:id/text1"

android:paddingTop="2dip"

android:paddingBottom="3dip"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:textSize="8dip" />

Performance comparison

PhoneGap’s plugins documentation states that all “heavy lifting” should be done on the native side since Javascript is still quite a bit slower while running in the native browser.

Since both of these solutions are composing the file list natively, it’s safe to assume that the PhoneGap solution is going to take longer given that the Javascript must trigger the native function, wait for the callback, and then build the list in html. But the question is how much longer?

In order to find out, I tested both apps against my 8 GB class 6 micro SD card, which has ~7.5 GB worth of data. The native solution consistently clocked in at ~1.5 seconds to build the list and bind to a ListView. The PhoneGap solution was all over the place during my tests. Some tests took as long as 13 seconds to complete, while others took only 3.5 seconds. The average time was around 6 seconds and, interestingly enough, the more times I repeated the test without restarting the app, the quicker it went.

Conclusion

Due to the fewer lines of code, speed, performance stability, and the ability to use native UI elements, I believe that doing things natively is a much better approach than using PhoneGap plugins. While it’s incredibly powerful to be able to extend PhoneGap, I think once you’ve gotten to that point, it’s time to consider a completely native solution.