Here follows my notes on writing a simple application using Appcelerator Titanium. Appcelerator Titanium allows you to build cross-platform native applications for mobile using Javascript. Since I’m currently posing as a Javascript fan-boy I thought I’d take a look.
Installation
Installation is fairly straight forward - and there is plenty of documentation, thanks to quite a verbose getting started guide.
The steps are fairly simple:
- Download, install and set up the Android SDK
- Download and execute Titanium
The first time Titanium runs it will offer to install in either the your /home/ or /opt/ folder. If you decide to install in the /opt/ folder then ensure that you have the necessary permissions - Titanium just disappears if you’ve not got the correct permissions.
Once all the packages have been downloaded and installed then you’ll find that the '~/.titanium/' folder has been populated. This appears to be where Titanium stores all of it’s application code. To actually run Titanium, just re-run the executable you installed - this time when it loads you’ll find that the Titanium application appears.
g_malloc_n error
If Titanium fails to appear then check the console output. I found that I had the following error:
./Titanium Developer: symbol lookup error: /usr/lib/libgtk-x11-2.0.so.0: undefined symbol: g_malloc_n
A quick Google led me to the Titanium forums with the following solution:
rm ~/.titanium/runtime/linux/1.0.0/libgobject*
rm ~/.titanium/runtime/linux/1.0.0/libglib*
rm ~/.titanium/runtime/linux/1.0.0/libgio*
rm ~/.titanium/runtime/linux/1.0.0/libgthread*
Initial update
When Titanium first loads it dials home and checks for any software updated. If there are any software updates they will be applied automatically - but it’s worth re-starting Titanium once they are installed. When I downloaded Titanium the mobile development was installed as an update - so when I tried to load any of the mobile examples Titanium was missing some of the vital user interface components.
Getting Started
The KitchenSink
Over on GitHub you’ll find the Titanium KitchenSink. This project contains examples and tests of all the components provided by Titanium.
Clone the repository using the following command:
http://github.com/appcelerator/KitchenSink.git
Once the sources have been downloaded you can load it from Titanium. In Titanium hit the “Test & Package” tab and click on “Run Emulator”. At the bottom of this window you’ll see an SDK and Screen selector. These settings decide which virtual device Titanium will attempt to execute your application on.
Hitting the “Launch” button will run the selected virtual device and install the application.
Oddly enough, this didn’t work for me first time. A virtual device would boot up, but the application would not appear. Delving into the KitchenSink directory you’ll find a build/android/bin/ folder. If the application is built successfully then you’ll see a app.apk file. When I installed this using adb install app.apk I got the an [INSTALL_FAILED_MISSING_SHARED_LIBRARY] error. This means that the virtual device being used does not have any of the Google APIs required by the application. To resolve this problem I opened the Android SDK, removed the “titanium_8_HVGA” virtual device, and created a new one ensuring the SDK requirements included the Google APIs.
Once the KitchenSink application has launched on the emulator it’s possible to see what is possible using Titanium.
User Interface
Titanium basis it’s user interface around Views and Windows. Windows contain Views and Views can contain all kinds of widgets, and possibly some move Views. You construct your interface using Javascript - so to create a button you’d use the following code:
var button1 = Titanium.UI.createButton({title: 'Button Text'});
button.addEventListener('click',function(e) {
Titanium.API.info("BOOM!");
});
When you create the widget you have to define a set of properties. These properties are different depending on the widget, and are all listed in the API reference documentation. Unfortunately you’re not able to manipulate all of the properties at runtime. Each widget has a number of methods for this purpose.
The addEventListener allows you to execute some Javascript when the button is pressed. One hic-up - If you’re creating a View containing a View with a number of widgets you aren’t able to listen to events on the individual widgets. You’ll have to listen to the event on the encompassing View. To identify which widget triggered the event you’ll have to use the clickName property. For example:
button = Titanium.UI.createButton({
title: '+',
width: 60,
left: 240,
top: 5,
bottom: 5,
height: 34,
clickName: 'add'
});
view = Titanium.UI.createTableView( { data: data , top: 5});
view.addEventListener('click', function(event) {
if (event.source.clickName === 'add') {
QuickList.Todo.add(add.textfield.value);
} else if (event.source.clickName !== 'textbox') {
QuickList.Todo.complete(event.index, event.rowData.title);
}
});
Local Storage
Titanium also provides some APIs for SQLite3 storage on the device. The following code will create a database handler, named db and create a very simple schema.
db = Titanium.Database.install('../quicklist.db', 'quicklist');
db.execute('CREATE TABLE IF NOT EXISTS DONE (title TEXT)');
db.execute('CREATE TABLE IF NOT EXISTS TODO (title TEXT)');
The Titanium.Database.install method will create a database if one does not already exist.
The following code will list the contents of the DONE table and populate an array which is used to generate a TableView.
rows = db.execute('SELECT * FROM DONE');
while (rows.isValidRow()) {
data.push({title: rows.field(0), color: '#000'});
rows.next();
}
rows.close();
It’s important to remember to use the close() function on the result set, otherwise an exception will be thrown when you attempt to make another query on the database.
Debugging
The Titanium IDE does not give you any feedback as to why your application falls over. It’s best to launch ddms to see the LogCat. This will show you a stack trace which should include a line number reference to your Javascript.
This is obviously only the case when the error occurs in your own application. When writing my own test application I found that an error was thrown with a stack trace referencing Titanium’s classes. For example the following error occurred when inserting a new row into a table
ERROR/TiUncaughtHandler(2804): java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2
ERROR/TiUncaughtHandler(2804): at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:257)
ERROR/TiUncaughtHandler(2804): at java.util.ArrayList.get(ArrayList.java:311)
ERROR/TiUncaughtHandler(2804): at ti.modules.titanium.ui.widget.tableview.TiTableView$TTVListAdapter.getItem(TiTableView.java:158)
ERROR/TiUncaughtHandler(2804): at ti.modules.titanium.ui.widget.tableview.TiTableView$TTVListAdapter.isEnabled(TiTableView.java:239)
Having IndexOutOfBoundsExceptions being thrown by the framework doesn’t inspire me with confidence. In this case I had to resort to commenting out lines of code in order to identify the offender. It transpired to be this:
table1.appendRow({title: title});
table2.deleteRow(index);
Where table is a TableView. The title variable was a reference a row title which was being deleted in the following line. The solution to this problem is to create a new variable for title instead of using the previous declaration.
This isn’t a major error, and my fix doesn’t necessarily indicate that the problem lies with Titanium or not. I have concluded though that although Titanium provides you with a rapid development environment when an error occurs, you’re likely to have to resort to using the same debugging tools and methods which you’d use for native development.
It would be nice to be able to import a Titanium project into Eclipse and use the debugger available for that IDE.
Testing on a device
Unfortunately I wasn’t able to use the Titanium IDE to run my application on a device. The progress bar would appear on the user interface, but it didn’t seem to do anything.
I found that you could just install the APK files designed for the emulator on your device. Navigate to the build/android/bin folder of your project and use the ADB utility.
adb -d uninstall com.owengriffin.quicklist
adb -d install app.apk
The first command removes the application from the device, the second will install it. Replace my package name with the package name of your application.
Analysing the standard output
The Titanium IDE wouldn’t create a distributable APK for me. The progress bar appeared, but nothing happened. This was a result of not reading the documentation through completely. It’s easy to accidentally skip sections. It’s annoying when you don’t realise for hours. When something doesn’t appear to work in Titanium examine the standard output (stdout) of the application. This is easiest when you run it from a terminal window.
The Titanium IDE is split into 2 parts, a fancy user interface and a bunch of Python scripts. It’s possible to see which Python scripts are being run from the standard output. It’s not possible to see the result of these scripts - to do that you have to copy the command into a terminal window and execute it there. For example the standard output for Titanium when running the Distribute command gave me the following:
[Titanium.API] [Information] (JavaScript.KKJSList) [ "/home/ogriffin/.titanium/mobilesdk/linux/1.4.0/android/builder.py", "distribute", ""QuickList2"", ""/usr/local/share/applications/android-sdk-linux_86"", ""/home/ogriffin/workspace/QuickList2"", ""com.owengriffin.quicklist"", ""/home/ogriffin/Dropbox/keystores/android.keystore"", ""XXXX"", ""quicklist"", ""/home/ogriffin"", ""9"", ]
You can see from the above that Titanium runs the builder.py script with the options provided by the user interface. It’s worth noting here that your keystore password is sent in the standard output, this isn’t ideal from a security perspective.
So the reason why Titanium wasn’t creating a distributable APK for me? My password for the keystore was different from the key password. Once I’d set the keystore password to match the key password everything worked fine.
Of course this is mentioned in the Publishing to the Android Market guide - if you read it correctly.
8 hours later..
Appcelerator claim that on of the main advantages of using Titanium over writing native applications is the speed of development. To a certain extent this is true. Coming from a web development background it is easier to use Javascript and HTML than it is to learn a completely new language, whether it is Objective-C or Java. However using Titanium still forces the developer to test their applications on either the debugger or on the device. Although closer to representing a real environment deploying to the emulator is slow, due to the longer build process of Titanium applications.
The tool itself - the helper application which builds your Titianium - was buggy and sometime unusable. Often it would crash and require a restart. Most of the time it wasn’t immediately apparent that the application had crashed - the user interface just stopped responding. The application would be better if it showed the commands which it executes.
I’ve not yet managed to test the cross-platform abilities of Titanium - that’s next on my list. Also on my radar is PhoneGap a similar toolkit.