Pitfalls - Getting Dojo onto iPhone and Android with PhoneGap

Now that I’ve cut my teeth on web development with my new-ish website, I’ve decided to go dental and start making some phone apps using HTML5, CSS, and JavaScript. After having played around with jQuery for my website, I realized that the code began to grow to the point where just managing it was becoming a tough issue. For a large app, a framework (and not just a library) is necessary, in my view. For this, Dojo, I choose you!

Dojo Pokeball
Yes, I drew that. Strange feelings of shame and pride pervade my whole body.

Dojo is a lot different from jQuery-land. While plugins in jQuery are extensions of the jQuery object, Dojo’s approach in the latest 1.7 version has been a game-changer, opting for the AMD (Asynchronous Module Definition) structural approach. I’m not going to go into the specifics of AMD (especially since I’m still learning it!), but Dojo has a fantastic documentation section complete with tutorials and API glossary hotness.

How to get HTML into an iPhone or Android app, you ask?

There are a few SDKs out there to get your webapp into the App Store or Android Market, one of them being PhoneGap. Now, if you want to make games specifically be warned! PhoneGap puts your app into a WebView, essentially a chromeless browser window, and wraps it with native code, exposing things like the phone or tablet’s accelerometer, camera, and GPS to your JavaScript. But for making games with <canvas> or WebGL, I’m learning, WebViews are slow. You’d probably be better off with another method — some I’ve seen tossed around are ImpactJS, CocoonJS, directCanvas, and Game Closure. These utilities claim to accelerate your mobile HTML code by leaps and bounds, and are worth looking into.

With that said, I’m not going to show you how to get PhoneGap running on your phone with Dojo. There are plenty of articles about that already. I will say be attentive if you’re using Dojo 1.7, though.. it’s fairly new and many tips out there still use the old and radically different 1.6 syntax. Instead, I’m going to tell you about a few pitfalls I ran into while getting Dojo onto my iPhone and Android phones, that aren’t heavily documented on the web.

JavaScript Obfuscation

Since PhoneGap wraps your webapp in a native code container, a clever person will be able to open that container and see/copy all your code. I tested this by viewing the /Applications directory on my iPhone. You can actually use a terminal to peek inside apps, and your PhoneGap app will expose all the files in your www directory in plaintext. So obfuscation could be important to protect your hard work.

Dojo from a CDN vs. a Local Copy

When dropping Dojo into your HTML file, you can choose to either drop a script tag that references a server that hosts the library online, or you can download a copy of the library and reference it in the script tag locally. For mobile apps it can be a tricky decision - you might want your users to be able to use your app when off the grid, but since Dojo can be more than 50MB (!), you might be hesitant to pack your own copy. I chose to stay local. Doing so gives me more control over Dojo’s options, and I’ll explain how you can reduce that filesize in #5.

Dojo’s Option, async:1, Works on iPhone, but not Android

Dojo 1.7 introduced the ability to load modules asynchronously, allowing developers to load into the app only what they needed. This gives us the ability to reduce the load and bandwidth usage on servers and end-user devices, and makes our code tight and light. Basically, the application loads only the base Dojo modules at first, and as your app requires other modules, they are loaded on demand from either the server or the local copy. This works swimmingly on iPhone, but unfortunately, not on Android. There seems to be an inherent problem with Android loading scripts asynchronously, as Dojo intends. Therefore, you have to use the Dojo Build Script, which I touch on in the next section.

Dojo’s Build Script Saves the Day

Usually a developer would use Dojo 1.7+ to load modules in as needed, but there are great advantages to using the build script. It’s a tool run via command-line that, using an install of node.js or Java, allows you to specify each module you use in your application in order to combine and minify those files, and only those files, into one script. Using that script instead of the usual dojo.js script allows your app to work perfectly and makes it light. It also makes your Android async problems disappear. No scripts are dynamically loaded; they’re all included in the script you built. The build script has a number of options, including being able to parse your HTML file for required modules. That didn’t work for me, so I found it essential to create a profile, as Björn explains. Dojo has more documentation on your build script options. If you want to follow what worked for me, navigate to the buildscripts folder and use the command ./build.sh action=release profile=profiles/myBaseplus.profile.js -r, replacing ./build.sh with build.bat if you’re on Windows and myBaseplus.profile.js with the profile of your making, and you’ll be A-OK.

deviceready vs. dojo/domReady!

Web developers know they shouldn’t start their JavaScript before the DOM is ready because the content of the page hasn’t loaded in order to be manipulated by their code yet. Dojo has a built-in module to make sure you can fire your code when the DOM is loaded, and that’s by including the module, dojo/domReady!, which is very similar in function to jQuery’s $(document).ready() call.

PhoneGap has an event of its own that fires when all the device’s native gadgets are available to use in JavaScript, and that’s the deviceready event. They set up your sample HTML document to include an onload attribute on the body element that will add an event listener for this event as soon as the body content has loaded. However, this can occur at any time, before or after the DOM is ready. Therefore, if you’re using any of the native functionality of the device, like its accelerometer, for example, it’s advisable for you to put your main block of code into the deviceready event listener’s callback function, and not use the dojo/domReady! module. And immediately I’m gonna contradict myself. Read on.

deviceTheme, or: How I Learned to Stop Worrying and Love the DOM

I’m guessing that if you’re looking to use Dojo on mobile, you’d be happy to have some automatically-loaded native-looking themes included! For instance, check out this sample tweet app Dojo showcases. Wouldn’t it be awesome if those styles magically applied themselves to your iPhone or iPad app, and Android styles to your Android app, and so on? Well, Dojo serves this up to you with very little work to be done on your part. All you have to do is load the deviceTheme module and call the parsing function that the dojox/mobile/parser module provides. It’ll parse your HTML document for views that you have written declaratively into any element attributes. This is all a part of the dojox/mobile and dojox/deviceTheme modules and I won’t explain it here — instead, check out how they made the tweet app, Tweetview, for details.

If you want to use the deviceTheme module in your PhoneGap application, I will suggest that you don’t include it in the deviceready event listener callback as I mentioned above. I tried it, and apps in both Android and iPhone displayed an ugly, unstyled HTML document for a few seconds until deviceTheme kicked in. I was able to work around it by using the dojo/domReady! module in the <head> of my document only to start the mobile parser, then loading all my main code from the deviceready callback. Also, you’re going to want to copy the directory structure for the themes’ css files into your dojo base directory as they were when you downloaded your local copy of dojo. Include only the dojox/mobile/themes directory into your project — if you used the build script to build your singular js file, you’ll need nothing else.

Misc

Best of luck to you on your mobile and other projects! Hopefully your work is now easier.

Comments