For the last few months as a part of my university studies I have been writing up some course materials for a mobile device workshop. The document that I ended up writing for that grew much more than what I expected (over 100 pages) and barely scratches the surface of the topic. However this is more a review of Titanium Appcelerator.
Being a Mac person I have a bit of a bias towards iOS. This is also borne out by me owning an iPhone which means the platform is natural to me. Android ends up frustrating me no end with its flawed and missing support for items. A great example is the constant battle to connect to my university wifi network. I had managed to get it working last week with our testing Samsung Galaxy S but this week it stopped working. Apparently the network is broken however I haven’t had any problems with my iPhone which still appears to connect and work like normal. But I digress, Android seems user unfriendly – or at least unfriendly to me.
So I set up Titanium Developer on my Mac. I have various versions of XCode and the iOS SDK installed already so I had to acquire the Android SDK. That was relatively easy where I downloaded the base applications and then installed all of the SDKs. The important thing, that I found out later, is that the normal API’s aren’t sufficient: you need all of the Google APIs. It turns out to be a lot of data so you might want to be selective for a particular platform (Android 2.2 + Google 2.2 API’s). So that all gets installed and for Android you tell Titanium where it is (XCode and iOS lives in /Developer and is easy to find).
The next challenge is to get your program up and running in the Android emulator or iOS simulator. This turns out to be easier said than done for Android and often less than 10 seconds for iOS. In my timing Android’s emulator almost always took minutes to start the emulator. Some times the emulator wouldn’t load properly and other times Titanium Developer wouldn’t recognise that the emulator had successfully launched. In these cases you ended up terminating the emulator and starting again. This ends up taking minutes to launch. Eventually the emulator gets itself up after a few minutes (or many more if it fails) and then the application deploys. You find a bug or make a change then want to re-deploy and test on the device. So fortunately for Android you don’t have to restart the emulator, it simply redeploys the application however even this process takes over 45 seconds! This means there is over half a minute of deployment difference between Android and iOS.
Because of this I started heavily developing on iOS and not bothering to test on Android. I didn’t feel that I had the time to waste waiting for Android to launch and be available to me as a developer where as iOS in some cases would be there in a few seconds ready to use (10 seconds at the most). It even kills the simulator and starts from scratch with a clean launch.
The problem that you then end up with the situation where I developed for iOS but didn’t test it on Android. I had faith that if it worked properly on iOS then it would still work fine on Android presuming I didn’t use any “platform specific” functionality. The problem is that it very quickly gets to a situation where everything doesn’t work properly on Android and it requires lots of time to fix the issue. Cross-platform? Not really.
Some of these issues arise from basic differences between the platforms. Android features a lot more hardware buttons including a “menu” button which can popup a menu over the screen to click. The menu is a great way of hiding stuff away and removing it from view. This is important when you don’t have much screen space to begin with however coming from an iPhone perspective where everything is visible on screen some how (even if it is a menu option that hints at more possibilities) this turns out to be rather frustrating as you click through almost every screen until you get to the point where you need to click the menu to progress. iPhone presents everything on screen with hardware buttons to change the volume, a mute/orientation lock toggle, a lock/unlock button and a home screen button. In iOS5 the volume control will also be a shutter button via software control. The flip side is almost anything you want to do is available on screen. There are a few exceptions around pressing down and holding parts of the UI (particularly with text, text boxes, the keyboard and links) which can trigger an extra popup/popover to appear however the norm is very much to have it visible on screen. This means that iOS has a strong UI interaction based around either tabs (bottom of the screen), the “navbar” with back and forwards buttons (top of the screen) or both.
When using Titanium we run into complications. On iOS you could use a tab group and the navbar is free. It automatically puts in the back buttons and the next button (“rightNavButton”) needs to be delivered but all in all not too bad. On Android there are tab groups but no navbar which means you’re using menus. Menus aren’t available on Android but give more UI flexibility than on iOS through having more options. The trap however is that menus and tab groups don’t work together on Android. I’m not sure if this is a Titanium issue but all I know is that it doesn’t work properly when using Titanium. The extra trap is that tab groups and the navbar works fine for iOS applications launched from Titanium’s main context (“app.js”) however on Android you can’t use a menu here. So if you want a menu on the first screen in the app you need to open another window first to create an Android activity to then associate the menu with the window.
And this in itself reveals another slight difference. There is the concept of “heavy weight” and “light weight” windows. iOS doesn’t appear to make any distinction but it very much matters on Android. Another Android feature is the hardware “back” button which permits the user to go back through the interface like a stack. On iOS this is implemented as a top left button on the navbar as a convention however it complicates Android because you end up with the two types of windows. Heavy weight windows create a new context and can be an anchor while light weight windows are ignored. If you open a heavyweight window, then a lightweight window and then click the “back” button the app doesn’t go back to the heavyweight window but to the one BEFORE that one. This may even result in the app quitting. The work around ends up being that all windows have to be heavyweight to prevent a click of the back button going somewhere it shouldn’t.
So once you start working around these platform specific quirks and features you end up with the bugs. One bug I encountered was that setting a top and bottom value for an item would work great on iOS but on Android those values appeared to be added to the parent view or window pushing it down. This perhaps became most obvious when I added a multiple text area option which caused the following undesirable result:
Clearly this isn’t what was intended however the same code works beautifully on iOS devices. I’m not sure if it is a case that I’m doing it wrong or what but fundamentally it is a mismatch between the two platforms. In some cases the problems were that I was using the API wrong and each respectively platform is more tolerant of the others though this only trapped me once or twice. In one situation I was using a platform specific call that wasn’t guarded so it wasn’t run on the other platform which resulting in a weird error that I didn’t fully understand until I took a closer look at the documentation.
And reviewing the documentation is important because on some pages you see a little Apple and little Android logo at the top of the page to signify that it is available on either however you also end up with situations where stuff is only partially available on either. This is distinguished by the text “iOS only”, “Android only” or rough equivalents (yes it isn’t uniform) after the name of the function. In some cases there are also significant behavioural differences. The Titanium.Geolocation.getCurrentPosition call will NEVER (emphasis from Titanium documentation) activate radios on Android instead returning a potentially very stale result. The documentation notes that iOS may activate radios depending if it considers the location data to be “stale”. This means that the most logical and obvious function call doesn’t necessarily make sense to use. The aim of using an abstraction platform like Titanium is that those platform specific differences are abstracted away. Perhaps adding a “maximum age” parameter to the function and then have Titanium automatically do the work needed to update the location details (it is possible by setting ANOTHER handler on the location event to get the position which is the work around I ended up using but that obviates the benefit of having the data cached and not causing a battery drain). Documentation in general is dodgy with this great example from the Titanium.UI.IPad page:
It is clear from using Titanium on both platforms that it was originally written with iOS in mind and Android has been tacked on as an afterthought. I’d hate to see what the Blackberry work is like though given the inconsistency between iOS and Android I’m not expecting the Blackberry experience to be much better again.
To make my life easier I constrained my platform to HVGA Android and iPhone. For what I was doing I deliberately excluded working on different platforms and screen resolutions instead hard coding values. Some of this was due to iOS bugs where setting “width: auto” or “width:100%” resulted in child items not receiving touch events on iPhone. This meant that shifting it to a larger screen (e.g. iPad) or changing the orientation presented much white space. However more worryingly I tried out the application on a Samsung Galaxy S running Android 2.1 and the app looks completely different. So this is a screenshot of the emulator running the application:
The interface is almost unreadable shifting from the emulator to the Galaxy S. Fortunately clicking on a textbox and rotating the device yields a full screen edit interface which conveniently provides you with a next button but no indication of what you’re typing into (this isn’t a Titanium issue, but an issue with the Galaxy S or Android; I had a similar problem where I accidentally typed a password into the wrong text box in the WiFi dialog when it was asking for a second username not the password as I was expecting). Perhaps I need to do something more however on the iPad the application renders without issue beyond the immense white space:
This leads me to one final issue with the platform: there appears to be no way to flexibly build a layout using Titanium Appcelerator for multiple screen resolutions that works across platforms. For iOS this isn’t so much of an issue because there is only two resolutions at two orientations (four potential combinations for layout). This means that programmatically setting the values requires at most a combination of four options. Everything else is consistent across the platforms which is useful. However that isn’t the case for Android. Android supports multiple device resolutions at increasing amounts, particularly with the introduction of the various tablet devices. This can cause a pain and perhaps I’m using their layout system wrong with the offsets and sizing however it almost feels like a requirement given the cross section of bugs that I see. The simple vertical style layout work nicely however as soon as you need to mix up the layouts you’re out of luck. Again, perhaps I’m doing it wrong but the most obvious way of doing things seemed to work well on iOS but not so well on Android.
The majority of the project was delivered using Titanium Developer and Aptana Studio. The combination worked reasonably well though not as smooth as perhaps the tool integration options that Microsoft or Apple provide – or even to a lesser extent Google with the Java for Android. There is a distinct lack of debugging support so you’re left with logging stuff as your primary method of debugging any buggy application. This means you don’t have a rich interface like XCode to profile and debug an application which is a great loss. The logging worked nicely however iOS 4.3 gave me grief and didn’t appear to work, targeting 4.2 got it back in action though. Logging consistently worked on Android even if I had to sometimes launch the emulator multiple times before Titanium would properly attach and deploy to it. I never had this problem with the iOS Simulator even if the application itself didn’t work. This leads also means that once the Android emulator is up and running you don’t want to quit it however periodically restarting the emulator can fix things. One case in point was when I was working on the location API code it would refuse to say it had an internet connection. I restarted it and everything worked fine there after but that didn’t save me spending an hour trying to work out why my code was broken.
Appcelerator have released Titanium Studio which is an updated copy of Aptana Studio (they bought Aptana) and includes support for their new 1.7 SDK. I didn’t see much of a difference in the SDK for what I was doing and all of the issues I saw with the 1.6 SDK was still present so I’m not sure what they changed however it didn’t break any code so that is a positive. Titanium Studio does feature autocomplete that works, continues their formatter. They’ve dropped support for JSDoc or similar automatic formatting for functions which is a disappointment (Aptana Studio would automatically populate the doc block for a function with the parameters for the function which was good).
For me Titanium Studio was a great improvement. I never once had an issue launching the Android emulator (it was still slow however) like I would periodically have when using Titanium Developer. Using iOS Simulator was still smooth to use as well. Apparently the pro version of these tools (e.g. not the community free download) offer debug functionality. The “Indie” plan is USD$50/month and the “Professional” plan is USD$200/month. XCode 4 with the latest iOS SDK from Apple is USD$5 – however you’ve already paid this as it is a requirement to test iOS applications. So you get a full blown IDE with a graphical layout tool, debugger, profiler and a whole host of tools already then Appcelerator want you to pay another $50/month to get debugging for their platform? You have to pay to get access to API’s like GameKit and StoreKit that you would already have access to normally through the standard iOS SDK.
The benefit for Titanium is to build cross platform applications however the reality is that this is tricky enough as it is. You end up in the valley between the two peaks where you have to deal with both platforms enough times that it isn’t smooth and you lose any advantages. iPad is an interesting case where you have another UI metaphor again with a split view that you would then need to develop an interface to handle the metaphor popular on that platform. This is supported by Titanium (Titanium.UI.IPad.SplitWindow) however we’re now up to a third platform specific UI that needs to be handled. Where does it stop? Blackberry? Windows Phone 7? WebOS? Eventually the application is held together by checks for each platform.
I can’t count the amount of time I spent doing circles on something stupid trying to Google for answers, pouring over documentation and waiting for Android applications to take nearly a minute to redeploy. It was frustrating to have stuff work and not work or then have to rebuild the application because one platform needed something one way and another platform wanted it a different way. Android is even more frustrating because even though I had a 2011 MBP, it still like it is slogging along as slow as anything. Building this app was time consuming as I would spend days in some cases trying to work out why something was mysteriously failing – particularly if it did it on one platform but not the other. The only other time I felt so unproductive was when I was building a Java GWT+GAE application where I ended up with boat loads of classes just to have everything work well (mind you that was more Java’s excessive verbosity than anything).
It turns out the best documentation on Titanium are the forum posts asking how to do things and if something is broken. I found a great number of undocumented “features” and “bugs” through reviewing the forums. Google is often your friend though sometimes a trip to the documentation can be equally as enlightening when you read that you’re trying to use an iOS specific feature on Android.
- Quick Tutorial on Navigation Groups (an informative blog in general)
- Use TableView Tips
- Concise example of how to do a menu on Android
- Enabling fake GPS on Android
- Basics of Layout – This is a great comparison of the layout system
- List of Titanium Mobile Events – a concise list of each event for each part of the system in one place. Also listed on individual pages but not always easy to check
- How to use maps on Android – my app worked without this on the emulator and dev environments, I have a feeling it only matters to packaged apps
- Example of how to use a tab group
- Example of Android menu with notes about windows, activities and menus
- Blog about handling CRUD operations
- Example of creating a nav group manually
23 Comments so far
Leave a comment