Ever since the release of the first iPhone and the first official iPhone/iOS SDK, mobile computing has taken a huge leap into the handheld realm. Where only a few years ago, it was normal to see hipsters hunched over laptops while sitting at Starbucks sipping their lattes, and surfing the web on the free wifi; nowadays they've broken free from their local coffee franchises (although still addicted to the caffeine) and roam the outside world, still surfing websites but now on their iPhones over 3G connections.

So how do you, as a veteran web developer, take advantage of this phenomena to write really cool mobile apps that engage the user on a whole new level? Well, there are several ways. You can bite the bullet and learn Objective-C, CocoaTouch, iOS SDK, and spend several months writing a true, native iPhone app. You can stay in your comfort-zone and write mobile-sized HTML5 web apps that sit, hands-tied to your servers with very limited device-centric capabilities. You can cheat a little bit and use PhoneGap or some other library to write HTML5 mobile web pages that can be submitted as apps to the App store. Or, you can cheat a lot and use Appcelerator to write your code in a language you're very familiar with, on a cross-platform API with practically all the device capabilities available to you--all resulting in native apps that can be submitted to the App Store and the Android Market.

What is Appcelerator?

Appcelerator is hard to define. It's an open source framework that acts partially like a compiler and partially like a runtime. Without going into the nitty-gritty about how it does its thing, let's just say Appcelerator will take Javascript code built on top of its API and turn it into a native application for the iOS and the Android platforms. For the iOS platform, Appcelerator's Javascript API maps to the Objective-C/CocoaTouch equivalents; and for the Android platform it maps to the Android Java framework. After the code is compiled, you end up with the respective platform's native binary app. Also, Appcelerator has a third mode which lets you write cross-platform WebKit-based desktop apps. We'll only be concentrating on the mobile side of things in this article.

Appcelerator comes in two parts, Titanium Mobile SDK and Titanium Developer. The Titanium Mobile SDK is the heart of the mobile app writing framework. Titanium Developer is a fancy, front-end GUI that lets you set up various environment settings, run the code in a simulator, compile it for a real mobile device and even package it for distribution to the Apple Store. As a side note, Titanium Developer itself is written using the Appcelerator Desktop SDK.

Installing Appcelerator

Required Prerequisites:

Prerequisites if you want to run on an actual iOS device:

  • Pay Apple the $99/yr fee and register as an iOS developer
  • Create/download all the keys/certificates (just follow the directions they provide on http://developer.apple.com/devcenter/ios/ under the iOS Provisioning Portal)
  • Add your mobile devices to the developer account
  • Create an AppID for your app
  • Create a Provisioning Profile that binds your AppID to the various devices you registered (this is the way to get adhoc distribution to developer iPhones for testing)
  • Download all those certificates and provisioning profiles, install them and configure your Appcelerator app to use them when compiling, so the code can be signed correctly

Running the gauntlet of getting the environment setup to test on an actual iOS device requires another article entirely. However, once you get through it the first time, it gets easier. Just follow the instructions on Apple's site. Here, we will just stick with running things in the iOS Simulator.

You'll notice that an Android SDK must be installed even though we're only doing iOS development. This seems to be a nagging requirement in order for Titanium Developer to get going (things may get fixed in later releases so try it out without it first, but if it complains, go ahead and install the Android SDK).

Making a New Project:

  1. Create a New Project
    1. Open up Titanium Developer
    2. Select New Project
    3. Select Mobile as the Project Type
    4. Fill in the other fields (make sure App Id exactly matches the AppID you registered in Apple's developer website)
    5. Click "Create Project"
  2. You'll be taken to the Project Settings window (the Edit tab)
    1. Just click "Save Changes"
  3. Now click the "Test & Package" tab, you'll see 3 sub tabs:
    1. Run Emulator - Runs your program in the emulator
    2. Run on Device - Runs it on a developer iPhone/iPod Touch (you'll need provisioning profiles setup)
    3. Distribute - Packages up the app for submission to the App Store (or adhoc distribution to non-developer profiled iPhones/iPod Touches)
  4. Click on the "Run Emulator" tab and then click on the "iPhone" subtab Ensure that the SDK is the latest iOS SDK version and click "Launch"

If all goes well you'll see a bunch of messages scroll past while the project code is compiling, and then the iOS Simulator launches.

Congratulations, you've successfully run the skeleton code!

Modifying the Code

Open up the directory you told Titanium Developer to create, all your code and assets will be stored in the Resources/ subdirectory. You'll notice that it already contains the app.js skeletal code; this is essentially the entry point into your app (ie. your main() routine). You'll also notice iphone/ and android/ subfolders. This is where you keep assets that will override the default assets you have in your Resources folder for when you need to target the particular platform.

Now let's actually write some code, rename/move the existing app.js file to app.js.old (be aware that any file with the .js extension will get compiled by Titanium Developer by default even if it isn't used in your end product). Create a new file called app.js and enter the following code:

Ti.API.info('Creating a new root window');

var w = Titanium.UI.createWindow({ backgroundColor: 'white' });
w.open();


Ti.API.info('Creating Label');

var label1 = Titanium.UI.createLabel({
    text: "Name Please",
    backgroundColor: 'gray',
    color: '#000000',
    top: 20,
    height: 'auto'
});
w.add(label1);   // add the label to the window


Ti.API.info('Creating Text Input Field');

var textfield1 = Titanium.UI.createTextField({
    backgroundColor: 'green',
    hintText: "Type Here",
    height: 35,
    top: 100,
    left: 10,
    right: 10,
    borderStyle: Titanium.UI.INPUT_BORDERSTYLE_ROUNDED
}); 
w.add(textfield1);  // add the textfield to the window


Ti.API.info('Creating Button');

var button1 = Titanium.UI.createButton({
    title: 'Click Me',
    width: 150,
    height: 30
});
w.add(button1);   // add the button to the window


Ti.API.info('Adding an eventListener to the button');


// Here's the button 'click' event listener, 
// notice the second parameter is an anonymous function with
// a parameter 'e', this is the event dictionary.

button1.addEventListener('click', function(e) {
    Ti.API.info('Button was clicked, e is ');
    Ti.API.info(e);
    Ti.API.info('Text field has value ' + textfield1.value);

    if(textfield1.value.length <= 0) {
        alert("Enter your name please");
    }
    else {
        label1.text = "Hello " + textfield1.value;
    }
});

Click on the Simulator tab and launch the app. If everything works, you'll be shown a white window with a gray background label that says "Name Please", a text field and a button that says "Click Me". Go ahead and try clicking the button. You'll see an alert popup message telling you to enter a name. If you look through the button1.addEventListener callback function, you'll see where that alert() is coming from. Now enter your name in the text field and click the button again, this time you'll notice the gray label up top change to say "Hello xxxx" (where xxxx is what you entered in the text field).

You'll notice that we don't have any main() functions or event loops; all that stuff is handled by the underlying iOS SDK. We're developing on essentially an asynchronous event-driven model (similar to the Javascript model in browsers).

Congratulations on writing your first app! Your next steps should be to browse through and experiment with the various API methods available in the Titanium Mobile SDK found at http://developer.appcelerator.com/documentation. Also be sure to read the Getting Started guides: http://wiki.appcelerator.org/display/guides/Getting+Started+with+Titanium as well as the Getting Started with the KitchenSink demo app: http://wiki.appcelerator.org/display/guides/Getting+Started+with+Kitchen+Sink

Programming Notes

Old-School Debugging

The best way to debug is to throw Titanium.API.info('some debugging message') all over your code. You can also use the name Ti rather than Titanium (ie. Ti.API.info('some message') ) to save you from having to type so much. It's also worth noting that you can usually pass arbitrary objects/variables by themselves to Ti.API.info and it will try to print out the string equivalent of the object (if available). Ti.API.warn() and Ti.API.error() are also available for logging purposes (they'll show up in the Titanium Developer console in different colors).

Subtleties of createWindow()

You can pass in a javascript filename to createWindow() using the dictionary key url, this way you can modularize your code into smaller chunks. The createWindow() method will essentially fire off the new window in a separate thread and you won't really have access to any variables or functions within it after its launched. You can send initial data into the new window by adding arbitrary key/values to the dictionary parameter of createWindow. From within the new window script you can get access to those intial variables via the Titanium.UI.currentWindow variable. For example if you had code like:

  var w = Titanium.UI.createWindow({ 
    url: 'newWindow.js',
    foo: 'bar', baz: ['zab', 'rab'] 
});

then, within the newWindow.js file you'll be able to get access to foo and baz like so:

Titanium.UI.currentWindow.foo      // gives us 'bar'
Titanium.UI.currentWindow.baz     // gives us ['zab','rab']

The only way to get data back out of the window is to use the event handling facilities of the framework. And on that note...

Event Handling is powerful asynchronous communications stuff

Make liberal use of the event mechanisms of the framework to communicate between various threads and subsystems in your app. In addition to the built-in events, addEventListener can listen to any arbitrary event name you want. The complementary function, fireEvent allows you to fire any arbitrary event name you like, with any parameters you like, in a dictionary that gets passed on to the event callback function. Practically every object in the Titanium SDK has the ability to fire or listen to events. The most globally accessible object is the Titanium.App object: you can write an event listener to Titanium.App.addEventListener and do a Titanium.App.fireEvent from completely different areas of your app (see the example I provided above). This allows you a great deal of power for inter-thread communications (i.e., sending messages between windows and the like). Any number of event callback functions can be added via the addEventListener, and they'll all be called in turn when the event is fired. You can also remove a call back function from an event listener by using removeEventListener. If you fire an event that isn't being listened to, it will just be ignored, no harm no foul. Events aren't queued forever so if you aren't listening on an event when it's fired and you missed it too bad.

Here's a quick example (we'll attach the event listener to the global Titanium.App object):

Titanium.App.addEventListener('fooEvent', function(e) {
     // e will hold { bar: 'rab', zab: 'baz', 
     // and some other core event fields }
     Ti.API.info('fooEvent was called and ' +
                      'we got this event dictionary:');
     Ti.API.info(e);   
});

// ... meanwhile somewhere else ...
Titanium.App.fireEvent('fooEvent', { bar: 'rab', zab: 'baz' });

Closures will be your best friends

As your applications get more complicated, you'll be writing a lot of addEventListener type code throughout. It is essential that you keep in mind in what context that event callback function will get called, and what variables are available in that scope. If you create/assign an event listener function within a scope and make use of a variable that is only available in that scope, then when the listener callback function is actually called (some time later way outside of the scope), you may not have access to that variable any more as it has long since been destroyed. This is a common enough thing in Javascript and the workaround is using Javascript Closures. There are plenty of articles out there that explain it in great detail but let's just say it's a nice way to bind a scope to a function so that when the function actually does get called the scope is available along with the variables. Here's a way of writing that button1 'click' event listener more robustly using a closure:

button1.addEventListener('click', (function (lbl1, txt1) {
    return function(e) {
         Ti.API.info('Button was clicked, e is ');
         Ti.API.info(e);
         Ti.API.info('Text field has value ' + txt1.value);

         if(txt1.value.length <= 0) {
             alert("Enter your name please");
         }
         else {
             lbl1.text = "Hello " + txt1.value;
         }
    };
}) (label1, textfield1) );

I realize that it looks a little weird, but if you study it carefully you'll see that we are actually creating an anonymous function that takes two parameters (lbl1 and txt1). Then, we're immediately executing that anonymous function, passing in the variables (label1 and textfield1) as the parameters. We do all that in one shot. Now within the anonymous function, all we do is return another anonymous function (this will be the actual event callback function that the addEventListener will get). Notice the inner anonymous function has the event 'e' parameter. Remember that Functions are first-class citizens in Javascript and are treated like any other object (there actually is a Function class in Javascript) and that's why we're able to do this. Notice within the inner anonymous function we're using txt1 and lbl1 as the variables instead of the textfield1 and label1 we used before. What this accomplishes is the outer function creates a scope having variables lbl1 and txt1 and the inner function binds to those variables; now no matter where the button 'click' event callback function is called the scope of txt1 and lbl1 will be correct. It's tricky at first, but if you get into the habit of using closures for such event-handling assignments it could save you a lot of painstaking debugging later. On a somewhat important side note, given that there is still a reference to that memory/object the garbage collector won't be repossessing the memory space until the reference count goes down to zero (ie. the anonymous function with the closure goes away); this may not seem like a big deal until you realize you're developing for a small embedded system with very tight memory constraints.

Need More Help?

The API documentation can be found at http://developer.appcelerator.com/apidoc/mobile/latest . Be forewarned that the documentation is usually a few steps behind the actual code base, and quite possibly may be incomplete or incorrect. Experimentation and educated guesses are usually required when trying out new functionality. Alternatively you can search in the "Q&A" section of the developer site to see if anyone else encountered the same problems http://developer.appcelerator.com/questions. If you get really desperate you can start digging through the actual framework Objective-C code located in YourApplicationDirectory/build/iphone/Classes/.

Here's a big hint that took me a very long time to figure out. Almost every class that takes the form Titanium.UI.*View is based off of the Titanium.UI.View class so they inherit all of View's properties and methods. They can be used interchangeably whenever a View is required. Views are the workhorses of the Titanium GUI framework, they provide the rectangular regions upon which the GUI widgets are drawn.

One of the best places to get working examples for the Titanium Mobile API is the KitchenSink demo app. As its name implies, it has demo code for practically every feature offered by the API. You should be able to download it from the same servers you downloaded SDK from (http://developer.appcelerator.com/get_started) . Simply uncompress the downloaded archive and import the KitchenSink directory containing the tiapp.xml file (the Titanium project configuration file) into Titanium Developer. Then, launch it in the Simulator. Browse through the KitchenSink/Resources/examples/ subfolder to find the acual javascript code. There's quite a bit of undocumented code/features in there.

Troubleshooting Tips

If you ever come across an annoying bug in code (and you will) that you are fully certain should work (especially obscure low-level Exceptions that are thrown before crashing), and you can't seem to get past it, try clearing out the build directory. For iPhones, the build directory you want to delete will be YourAppsDirectory/build/iphone/build/ . Do NOT delete the outer build directory or you'll have to create the project from scratch again.

Worst case scenario: You may have to create a new project from scratch and copy the Resources and all the assets into it. I've had this happen a few times, especially when the Mobile SDK was upgraded.

iPhone App Development--Only Faster

Appcelerator is a fickle beast that's definitely rough around the edges and ever-evolving, but when it works (and when you get used to its quirky ways), it'll help you throw together a working iPhone app much faster than if you had to write it all from scratch in Objective-C. It's especially useful for the lazy web developer.