Sunday, June 3, 2012

Appcelerator Titanium: couldn't find module only on real iPhone device


Appcelerator Titanium is a great environment for cross-platform mobile application development.
However sometimes it fail with strange behavior. I've found a bug on commonjs implementation (or may be a restriction of iOS...) that prevents you to load a JS module using require function of CommonJS.
In fact, if you put a directory named "iphone" within the path to the module, it will run fine on simulator but will fail to load on real device (I'm using an iPhone 4s with iOS 5.1) displaying a message like "Couldn't find module: /path/iphone/to/module".

Let me show you how to reproduce the error:

- Create a new Titanium Mobile project

- Now create a directory structure inside Resources like the following:

  • test/iphone
  • test/other


- Create a JS file named "ThisModuleWillLoad.js" into "test/other" directory with the following content:

 exports.test = function() { alert('From ThisModuleWillLoad!');}  


- Create a JS file named "ThisModuleWillFail.js" into "test/iphone" directory with the following content (just to set something in the module):

 exports.test = function() { alert('From ThisModuleWillFail! This message should not be displayed on real device!');}  


- In your app.js put following code:

      var moduleWillLoad = require('test/iphone/ThisModuleWillLoad');  
      moduleWillLoad.test();  
      var moduleWillFail = require('test/iphone/ThisModuleWillFail');  
      moduleWillFail.test();  

Run the app in iOS simulator and you will get two alerts as result of both "test()" method execution:
1. "From ThisModuleWillLoad!"
2. "From ThisModuleWillFail! This message should not be displayed on real device!"

Now install the app on your iPhone device and run it. This time, only one alert will be displayed because second module (ThisModuleWillFail.js) will not be loaded and a red error screen will be generated by Appcelerator Titanium runtime with the message "Couldn't find module: /test/iphone/ThisModuleWillFail".

I don't know the reason of this strange behavior, but if you need to separate the code based on platform (android, iphone, ipad, blackberry, etc.) don't put the string "iphone" in module path!

Probably the same behavior will be on iPad device, but by now I don't have an iPad so I can't test it. If you have an iPad and you want to do a test, please leave a comment!

On Android devices this problem is not present.

Hope this will help you to avoid losing time... ;-)