Some days ago I published a hack that allows patching the Titanium Mobile SDK for enabling fast on-device testing of iOS applications, without needing to rebuild, sign and redeploy them.
With this post I’d like to share some of the inner workings of the Titanium sdk that make that hack possible. I also try to explain in more detail how the hack works, so you may want to check out its source code at https://github.com/omorandi/TiiOSFastDev.
When deploying an application on the iOS emulator, the JS engine gets fed directly with the original files that reside in the
Resources directory of your app project, loaded at runtime. This allows you for example to see the changes you made in one file, by just restarting the app in the emulator.
On the other hand, when deploying on the device, the original source files are processed and packed into a single file, just before building the app.
This step generates the
build/iphone/Classes/ApplicationRouting.m file, which is one of the very few that are dynamically generated by the build process. Indeed, most of the objective-c files that compose the native app are simply copied from the appropriate Ti SDK directory (e.g.
/Library/Application\ Support/Titanium/mobilesdk/osx/1.8.0) into the
build/iphone directory of the project by the titanium build scripts when you launch the app from Ti Studio, or from the command line.
ApplicationRouting.m contains the definition of a dictionary object that associates the name of each JS file present in the Resources directory of your project with a binary representation of its original content, along with a single class method named
resolveAppAsset: whose only purpose is to return the appropriate file content for a given path:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
In other words, this portion of code represents the point where the original content of each JS file is dispatched to the Titanium runtime environment, which will then feed it to the JSCore interpreter.
As you surely understand at this point, the FastDev hack is made possible by simply using a modified version of the
resolveAppAsset method, which, instead of returning static data, opens a connection to an HTTP server running on the development machine for retrieving the original JS files from the Resources directory:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Since the method is called synchronously, also the HTTP request must be performed in a synchrounous way:
For testing the application on the iOS emulator, the request to the server can be made on
localhost, however, for on-device testing, we need to know in advance the IP address at which we the server can be reached, because the modified
ApplicationRouting.mwill be built into the native application running on the target device. This is achieved through a simple trick in the startserver.py script:
1 2 3 4 5 6 7 8 9
This code allows discovering the local IP address that routes to the Internet (specifically to gmail.com), so I make the assumption that the iPhone/iPad used for testing and the development machine reside both on the same local network and that the IP address of the Mac machine on that network is also the one that routes it to the Internet.
startserver.py script uses this information for patching the
build/iphone/Classes/ServerAddr.h file containing the
SERVER_ADDRESS define, which is used in
ApplicationRouting.m for creating the HTTP request. This is also why the
startserver.py script needs to be launched before building the app.