WebOS From Homebrew to Catalog: tips learned in the process

March 1, 2011
7 min. read

I’ve been a developer, on many different platforms, for just under two decades. Like many code monkeys, I enjoy learning new architectures. I’m not exactly sure why, but programming for WebOS has me more excited than I’ve been since working with GCC on the Palm Personal. The idea of building apps with web technologies on a portable device sounded interesting. I knew that certain things would be easy and others hard. That is always the case with any platform.

With Word Whirl queued up for release in the App Catalog, I decided it might help others to describe some of the things I’ve learned. This is my way of giving back to all the PreCentral users that helped during the process of taking Word Whirl from a request post to a published application. Hopefully this will help some more make the leap from Homebrew to App Catalog and get more apps out there.

Debugging

When developing on the Pre or in the Emulator, it is difficult to locate syntactical and functional errors in your code. You will save a great deal of time when trapping errors as close to the source as possible. I include try/catch blocks around any non trivial code. A typical setup function might look like this:

MySceneAssistant.prototype.setup = function(){
    try{
        // My Code
        Mojo.Log.info(Hey, I actually got here.);
    } catch(e) {
        Mojo.Log.error(myScene.setup error: %j, e);
    }
}

When an error occurs, this will print a JSON encoded version of any JavaScript exception that occurs. For this to be useful, you need to read the /var/log/messages file. I generally only need to look at errors during initial development on the Emulator.

For the emulator, you ssh to port 5522 of localhost, using username/password of root/root. On a unix machine, type ssh -p 5522 root@localhost in a terminal and enter root when prompted for password. For Windows, you will use Putty, configured for ssh at port 5522, and enter username and password when prompted.

Once you have terminal access to the emulator, use the log command with your appId. Ex: log com.sachersoft.wordwhirl

Use Ctrl+C to exit the log command when finished.

Also in the function above, I have a Mojo.Log.info command to write out non-error generated debug messages.

Your messages will not show up unless you increase the logLevel. To do this, create a file named framework_config.json in the root of your application. Inside that file you need:

{
    "logLevel":99,
}

Remember to set the value back to 0 before you release your app or you will fill the users messages file with all your debug information.

If you need to debug on the Pre, you can only use Mojo.Log.error to write to /var/log/messages. Follow the process to get terminal access (or incorrectly called “root your Pre”). You will find the log command missing. tail -f /var/log/messages will partially replace this. To perform more like log, pipe the output to grep with something like this:

tail -f /var/log/messages | grep com.sachersoft.wordwhirl

Obviously, replace com.sachersoft.wordwhirl with the proper appId for your application. Like log, you can terminate this command with Ctrl+C.

Stability and Efficiency

The biggest problem I have seen in WebOS homebrew code is missing cleanup for event handlers. This can cause an application to use more memory than it really needs and opens up the possibility of memory leaks which can make your app be responsible for the users phone getting progressively slower.

A typical event handler statement in the setup function of a scene might look something like this:

MySceneAssistant.prototype.setup = function(){
    this.controller.listen('MySuperBtn', Mojo.Event.tap, this.tapButton.bind(this));
}

This functions correctly, calling the tapButton function and all looks well. However, when the scene unloads the event handler isn’t cleaned up properly. Every event handler must be removed in the cleanup function with a stopListening call. This is impossible to do with how we created the event handler.

Each time you call this.tapButton.bind(this), you will receive a different instance of a function, created by bind. (The same thing occurs with bindAsEventHandler.) We need to save the bound function instance, because the stopListening method requires the exact arguments given to the listen method.

MySceneAssistant.prototype.setup = function(){
    this.tabHndlr = this.tapButton.bind(this);
    this.controller.listen('MySuperBtn', Mojo.Event.tap, this.tapHndlr);
    this.controller.listen('SecondBtn', Mojo.Event.tap, this.tapHndlr);
}

Since the bind function call is stored, we can properly stop event listening. There is an added advantage if you have more than one user of the handler. Notice my new SecondBtn will use the same bound function as the first. This eliminates multiple instances of bound functions going to the same place, thereby saving memory. Now that we are creating event handlers properly, we need to remove them in the cleanup method.

MySceneAssistant.prototype.cleanup = function(){
    this.controller.stopListening('MySuperBtn', Mojo.Event.tap, this.tapHndlr);
    this.controller.stopListening('SecondBtn', Mojo.Event.tap, this.tapHndlr);
}

With the saved bound function this.tapHndlr, all arguments are the same as when listen was called and the event handlers will be properly disposed.

Scene Painting

On some of my scenes, I noticed the HTML elements flicker into place, when dynamic HTML changes were made in the activate scene. Since these changes can’t be performed in setup, how do we fix it? The answer is the little publicized aboutToActivate. In this example, I have a css class called “hidden” which is just:

.hidden{
    display:none;
}

I have a button I want to hide in certain cases. When this code was in activate, there was a short time that the button was visible before it disappeared. The flicker was very short, but it looked bad. By moving the code to aboutToActivate, this flicker is removed and replaced with just a slight bit more scene loading delay.

MySceneAssistant.prototype.aboutToActivate = function(){
    if(HideButton){
        $('MyButton').addClassName('hidden');
    }
}

The aboutToActivate function can be useful when any dynamic HTML changes have to occur at the load of a scene. Go through your app and look for flashing or movement of the display when dynamic content is loaded. This can make it better.

Use CSS3 Transitions

While some games require exacting animation with JavaScript timers and positioning code, that isn’t always the case. Almost all animations in Word Whirl are performed by CSS transitions. I define a base class for a given item. This class will define which styles to animate. Then I define as many classes as needed to represent the states I animate between. I set styles directly, instead of classes, when the values are more dynamic.

For the letters used to play in Word Whirl, I have a base class of letter-button. The positioning is absolute within my letter-board div. The other important pieces of this class are the two -webkit-transition styles:

.letter-button{
    position:absolute;
    width:45px;
    height:46px;
    background-image:url('../images/ltrtile.png');
    -webkit-transition-property: left, top;
    -webkit-transition-duration: 250ms, 250ms;
}

The -webkit-transition-property tells which styles the transitions should affect. -webkit-transition-duration defines the duration it takes to animate each property from start to stop value.

In addition, I have 6 home classes (home0 through home5) and 6 target classes (tar0 through tar5). These just define the left and top values for each location. Just the first two of each are listed below, as the others just use larger left values.

.home0{
    left:10px;
    top:50px;
}
.home1{
    left:60px;
    top:50px;
}
.tar0{
    left:10px;
    top:0px;
}
.tar1{
    left:60px;
    top:0px;
}

The HTML for a letter block is defined below. The inside div with letter class is just to hold the letter used on the block and not important for the animation. The letter-button class gives the block its main properties. The home0 class places the block in the first home position.

<div class="letter-button home0" id="but0">
    <div id="let0" class="letter"></div>
</div>

Animating the block is now just a matter of removing and adding position classes. This code would move the block from the first home position (home0) to the second target position (tar1).

$('but0').removeClassName('home0');
$('but0').addClassName('tar1');

The div will fly from the home0 to the tar1 position in a quarter of a second. The timing was controlled by the 250ms setting in the -webkit-transition-duration style.

That is how the letters fly around in Word Whirl. Obviously, the JavaScript to maintain the state, debounce the letters, and trigger the correct class changes is a little more complicated, but the two lines above is the only code doing the animation. As Palm enhances the webkit implementation, these animations will automatically improve with no changes to your code. Search for “webkit-transition” to see many examples available on the web, while keeping in mind that not all styles are supported yet in WebOS.

Don’t be afraid to completely rewrite and refactor portions of your code. It took two major rewrites to get Word Whirl into a form that I finally liked. However, the lessons learned will be second nature to your next programs.

comments powered by Disqus