Tuesday, December 6, 2011

Debugging Phonegap/Cordova Applications

When developing a mobile application with PhoneGap, there inevitably comes a point when things don't work as expected.

When this happens, I triage the application in the following order:

  1. Sanity Checks on the HTML and JavaScript
  2. Verify event binding
  3. Inspect variable values
  4. Wire protocol analysis

Sanity Checks

JavaScript is a Misunderstood Dynamic Language. Unfortunately, that rules out many compile-time sanity checks. The good news is that it doesn't rule them all out. JSLint is an excellent tool to add to your Eclipse environment to quickly look at your code for syntax errors. Personally, I turn off the options for whitespace checking and add a list of known, created classes and configure JSLint to inspect all javascript files in my project. This simplifies the checking of my own flaky code. The only downside is that other included libraries have to be cleared to remove "problems" in the output. JSLint can be very strict in what it considers acceptable JavaScript (=== versus == as an example). The easiest solution is to right click any 3rd party files such as the phonegap-1.2.0.js file and the jquerymobile/jquery javascript files and tell rockstarapps to clear javascript errors. This allows any errors in your own JavaScript files to show through in the Eclipse problems window.

Verify Event Binding

When verifying event binding, the easiest solution is a simple alert message. In many cases this is all that's needed. If you'd like to instrument your code further, you can use the console.log statement. This is visible in the IDE debugging window in many environments. console.log allows you to write out debugging messages that don't interfere with the flow of your application in the same way alert messages would. There are some notable exceptions where the device will not report the message. Most commonly, when running on a physical device (e.g. HTC Evo) console.log messages aren't logged in Eclipse. In these cases, you can turn to weinre (pronounced "winery"). This tool works by running a local server and communicating with this server from your PhoneGap Application. This is a fantastic bit of technology, but the setup can be a bit daunting. Fear not, the PhoneGap devs have provided a wonderful service at http://debug.phonegap.com/. This service allows you to enter a globally unique ID (I simply use my name). By inserting a javascript link with this guid, your mobile device can automatically route console.log information to the phonegap server where you can view the output. Communication is two-way, allowing you to highlight html elements and see the regions highlighted on the device. The latter feature is invaluable for identifying bits of dynamic content that didn't work out as planned.

Inspecting Variable Values

While developing applications, I tend to go through a large number of iterations simply in chrome. After developing the UI, I view it in chrome and use the inspect element feature to view details about the output. Using CTRL+SHIFT+I, I can bring up an environment that allows me to inspect CSS styles, step through javascript, and view the resulting HTML in the browser. The key to working well with this is isolating your user interface code from the device. As an example, I like to create javascript classes that have canned data in addition to the live server data. This allows me to eliminate data/network issues from the user interface. In the same way, I insulate the user interface from the physical device. This allows me to test my interface in a desktop browser without the overhead of an emulator (more iterations == faster development), and it allows me to rule out issues between PhoneGap and my own code (hint: it's always my code that's wrong).

Wire Protocol Analysis

If your user interface looks right with the data you're expecting, but you're not getting what you're expecting, it's time to rule out issues between the client and the server. In these cases, I like to use WireShark to capture the communication between the client and the server (again isolating the physical device as much as possible from the equation). Before selecting the network interface to capture on, I navigate in my application as far as possible before the issue in question. This reduces the junk I have to look through while debugging. You can definitely do this with filters in WireShark, but for the novice, it's easier to limit the incoming data.

Last Recourse

When none of these techniques solve my problems, I tend to post to the phonegap google group. I encourage all of you to do the same and please don't be shy if you have a possible solution to someone else's problem. Even if it isn't the perfect answer, it can set someone on the road to success.