Debugging Titanium Apps With Chrome DevTools
- fill the code with logging statements
It turns out that there are times when none of these techniques is satisfying: using logging statements is a quick and dirty technique, but it can lead to long modify/rebuild/test iterations, before finally finding the right spot in the code that’s causing an issue. Using a proper debugger, like the one provided by Ti Studio is surely the way to go in most cases, however, switching back to Studio just for debugging can be a painfully slow operation. In other words, I needed a more “agile” way to start a debugging session.
Enter Ti Inspector
Ti Inspector is a tool I had a lot of fun building over the past few months, which allows debugging a Titanium app (only on iOS for the moment) through the Chrome DevTools debugging interface, i.e. the same panel that can be opened for inspecting and debugging a web page in Google Chrome (e.g. right-click on the page, then Inspect Element).
How was this possible? Actually, the DevTools panel provided by Chrome is nothing more than a pure HTML+CSS+JS web application, whose source code is part of the Blink project, i.e. the fork of the WebKit rendering engine that Google recently started. When opened inside of Chrome, the DevTools front-end directly communicates with the Chrome internals through a series of JS to native bindings, however it can also be used in a remote debugging setup, where the front-end is served from and connects to a remote Chrome instance, running a web application we want to inspect. In particular, the DevTools front-end application expects to communicate with a remote backend counterpart through a websocket connection, implementing a JSON-based RPC protocol, which is documented in detail here.
--debug-host argument to the Titanium CLI invocation, for example:
$ titanium build --platform ios --debug-host localhost:54321
Ti Inspector is the tool that allows these two worlds to successfully communicate, acting as a gateway between the Chrome DevTools remote debugging protocol and the Titanium debugger protocol. It does so by the means of a node.js based application, which implements the following mechanisms:
- It serves the DevTools web app from the default port 8080
- It listens for tcp connections on the default port 8999, where the Ti debugger agent will connect once the app starts
- It accepts websocket connections from the DevTools app
- Once both the debugger agent and DevTools app are connected, Ti Inspector translates commands, replies and asynchronous events from one protocol to the other, doing additional book-keeping and translating the descriptors of the necessary model elements (i.e. scripts, breakpoints, stack frames, variables, etc.).
How to use it
Ti Inspector is a node.js module, so as a basic prerequisite a working node.js setup is needed, then we can use npm for installing it globally:
$ [sudo] npm install -g ti-inspector
Once installed, we can
cd to any Titanium Mobile application project directory and launch the
$ cd /path/to/your/titanium/project/directory $ ti-inspector
doing so, a web server starts listening on port 8080, and a debug server is attached to TCP port 8999.
Pointing a browser on
localhost:8080 we’ll get a page with a brief description of our application, telling that no active debug sessions are active. At this point, we can start our application through the Titanium CLI, specifying that the debug agent running in the app will need to connect to port 8999 on the localhost, for example:
$ titanium build -p iphone --tall --retina --debug-host localhost:8999
Once the app will start in the iOS Simulator, the debugger will connect with Ti Inspector and a new debugging session will be created. In the browser we can then start the DevTools app and start debugging.
Anyway, sometimes a screencast is better then thousand words, so you can check out this short demo:
- Breakpoints: setting/removing breakpoints, conditional breakpoints
- Call stack inspection (when execution is suspended)
- Variables and objects inspection
- Watch expressions
- Step operations (step over, step-into, step-out)
- Console logging
- Expression evaluation in the console (only when execution is suspended)
- Suspend on exceptions (disabled by default)
Ti Inspector is currently at an alpha stage of development. Some features are still missing and will be possibly added as they become indispensable (e.g. Android emulator support), while others will probably never taken into consideration (e.g. on device debugging).
For completeness, some of the current limitations are the following:
- Android is not currently supported: for debugging Android Apps, Titanium Studio does more heavy lifting and the Ti debugger protocol is somewhat translated into the V8 debugging protocol by an internal component. This means that supporting Android will mean implementing the V8 remote debugging protocol in Ti Inspector. This is something I’ll likely work on in the near future
- On device debugging is not supported since it’s treated in a special way by the CLI and Studio.
- Expressions can only be evaluated when the execution is suspended
The source code is completely available on GitHub under the MIT license. Issue postings and pull requests are very welcome.