Adam Mark

Web design and development

Introducing Chartlets: Tiny Charts for Tablet and Mobile Web Apps

I just put the finishing touches on Chartlets, a library for making tiny charts for mobile and tablet web apps:

While most data visualization libraries are biased toward big displays, Chartlets assumes the opposite. Not only are Chartlets small, the library itself weighs in at under 3K. And the API is drop-dead simple, requiring no programming knowledge to render a basic chart. Chartlets can be defined entirely in HTML:

<canvas class="chartlet" width="65" height="65" 
  data-type="pie" data-sets="[1 2 3 4 5]" data-opts="theme:money"></canvas>

Check out the full docs and examples at

App Cloud vs. PhoneGap: Which Hybrid-native Platform Is Right for You?

When I talk to developers about App Cloud, they often ask, “How is App Cloud different from PhoneGap?” Without missing a beat, I give my stock answer: “PhoneGap is great, but App Cloud gives you so much more.” The matter of more has always nagged at me—more is not necessarily better—so I decided to do an apples-to-apples comparison from a Web developer’s perspective. I built the same app twice, first with PhoneGap, then with App Cloud, and graded each system on the strength of its platform capabilities, development model, and service offerings.

Spoiler alert: Both App Cloud and PhoneGap are winners! Skip to the end to see my conclusions.

First impressions

PhoneGap: I located and downloaded the latest version of the PhoneGap SDK in about 15 seconds without any fumbling. This made a great first impression. And I noticed PhoneGap offers a public archive and full documentation of its old SDKs, which gave me peace of mind as a developer. Finally, I found to be neatly organized, with clear pathways to documentation, community support, and case studies.

App Cloud: I registered for a free account before downloading the SDK. (If you’re impatient like me, you’ll find the registration step annoying. But it’s necessary if you want to use cloud services like cloud compilation, push notifications, and analytics.) After registering, I landed in App Cloud Studio, where I found links to the SDK, the Workshop app, video tutorials and community support. I downloaded the SDK and the Workshop app.

Getting started

PhoneGap: I unzipped the SDK, cracked open the getting started guides, and followed the instructions for setting up my development environments on iOS and Android. What looked simple on paper turned out to be insanely complicated.

Getting started on iOS required downloading and installing XCode. But to download XCode, I had to upgrade my operating system to version 10.7 from version 10.6.8. This took four hours.

Getting started on Android was even more of an exercise in patience. I downloaded Eclipse, then the Android SDK, then the Android Developer Tools plugin. At each pass I was presented a dizzying array of options. For example, there were 12 versions of Eclipse and 11 versions of the Android SDK:

Whew! All told, getting started with PhoneGap took nearly a whole day, and I had yet to write a single line of code.

App Cloud: Getting started with App Cloud was a breeze by comparison. First I downloaded the Workshop app onto my iPhone and Android phone. Then I unzipped the SDK, double-clicked the Node.js installer, ran the startup script, and opened the App Cloud development server in my browser. In about ten minutes, I was ready to start coding.

Hello World!

PhoneGap: I opened XCode and followed PhoneGap’s “Hello World” instructions for creating a new Cordova iOS project from a shell script. This appeared to work until I tried running the project in the iPhone simulator:

As it turned out, the local copy of the getting started guide was out of date and omitted a key step: installing the Cordova library. I deleted the project, installed the Cordova library, and ran the script again. Then I tweaked index.html and opened the app in the simulator:

Nice! Getting the app onto my iPhone was a bit trickier. I had to register my device in the iOS Provisioning Portal, then create a provisioning profile, then create a development certificate, then install the certificate. While these steps are necessary to create an iOS app in any framework, it was cumbersome to go through these motions just to run my “Hello World” app.

As for Android, it once again threw me for a loop. I simply couldn’t get my “Hello World” app to run in the Android Emulator despite all my attempts to create and launch an Android Virtual Device in Eclipse. After a frustrating couple hours—even stackoverflow was no help—I managed to create a device image via the Android SDK Manager, then launch the emulator:

App Cloud: I ran the provided Node.js script to create a starter app inside App Cloud’s development server. Then I popped open Chrome and navigated to the app:

I made a few changes to a CSS file and refreshed the web browser—a quick win. Then I opened the Workshop app on my iPhone and scanned the QR code that appeared in the web browser. In three seconds, the app loaded on my phone. I made some more changes to the CSS and pulled down the “Refresh” tab in the Workshop. The changes appeared. Then I did the same thing on my Galaxy Nexus.

By now I’ve gone through this process a thousand times, yet I’m always floored by it. In just a few minutes, I was previewing an app on both iOS and Android, making changes, and seeing the changes take effect immediately. And I did it without XCode, without the Android Developer Tools, and without any specific knowledge of native app development.

Structuring the app

PhoneGap: I wanted my sample app, a simple news reader, to have two distinct views, one for displaying the latest news and one for displaying my saved articles. I assumed I could use two HTML pages to create the backing for these views, but I was surprised to learn that I had to build my entire PhoneGap app within the context of a single HTML page. I imagined my code would get pretty messy without using a JavaScript MVC framework to manage it, and I worried about the performance implications of doing too many things inside one page.

I was also disappointed by the lack of support for native navigation across iOS and Android, so I had to roll my own navigation in HTML. Not wanting to use an iOS-style tab bar on Android or an Android-style action bar on iOS, I settled on a generic design that would accommodate both platforms.

Finally, I found no built-in functions for handling basic tasks like scrolling and pagination. After exploring a few different UI libraries, I decided to install jQuery Mobile, a popular tool for building mobile web sites.

App Cloud: Unlike PhoneGap, App Cloud apps are backed by multiple HTML files, each corresponding to an independent view in the UI. A typical content-driven app might have four or five views, and the developer can choose whether or not to display native navigation to help the user navigate from view to view. In this sense, the UI is truly “hybrid.” On iOS, users see the familiar tab bar and “More …” menu; on Android, users see an action bar.

As I discovered early on, spreading code and functionality across multiple views is a good thing for a few reasons. First, the native container can unload individual views if it needs to free up memory (instead of crashing). Second, developers can neatly organize their code by view (each HTML page has its own DOM, its own CSS, and its own JavaScript). Finally, because the app is broken into multiple views, the code itself is more portable.

App Cloud has a thin UI layer, but it does 90% of what I need: “tap” events, smooth scrolling, and page transitions inside a single view. I like having these basic functions available out of the box. As with PhoneGap, App Cloud lets you drop in third-party JavaScript libraries. (I’ve used many, including Moment.js for date formatting and Hammer.js for gesture support.)

Another nice feature: App Cloud loads HTML “templates” from plain text files on the device’s file system and populates them in the bc.templates object. This makes it easy to separate control logic from presentation logic using Markup.js (included in the App Cloud SDK) or a templating framework of your choosing.

Making the app

PhoneGap: Even though I was able to use my favorite text editor and stage the app on a local web server (Apache), I still had to run XCode and Eclipse in order to build and preview the app on my iPhone and Nexus. Every few minutes I went through the same motions: 1. Switch contexts from my text editor to Xcode, then to Eclipse. 2. Run the app in the iPhone simulator, then in the Android emulator. 3. Deploy to each device. This got tiresome. (I looked at PhoneGap Build as a potential time saver, but it didn’t strike me as a convenient development tool. It’s a build tool, as the name implies. I also looked at Hydration but got scared away by the docs. What’s a “non-Hydrated binary equivalent?”)

At this point it occurred to me that I was dealing with two different code bases to make two different apps, one for iOS and one for Android. A fellow engineer suggested I create a symbolic link between the www directories in each project, which seemed kludgy to me.

App Cloud: I staged my app in App Cloud’s local development server (running on Node.js) and tested much of it in Chrome. When it came to testing the app on my iPhone and Nexus, I simply loaded it up in the Workshop app.

The Workshop app extends the development model that all web developers have come to know: Code, refresh, repeat. The ability to test an app incrementally—without long delays and without having to reboot the app—saves a tremendous amount of time and frustration.

Finally, unlike PhoneGap, I was working with a single code base of HTML, CSS, and JavaScript files, even though I was building for iOS and Android at the same time. There was simply less code to move around.

Working with content

PhoneGap: I pulled an RSS feed directly from my web site using jQuery’s get() method. Then I converted it to JavaScript object with the help of an XML to JSON plugin. To cache content on the device, I used Local Storage methods.

App Cloud: As with PhoneGap, I used $.get() to pull down the RSS. When it came to storing data on the device, I used bc.core.cache(), which uses a Least Recently Used algorithm to clear data if the cache ever fills up. App Cloud’s caching function also handles serialization and deserialization of objects.

Taking it a step further, I decided to run my data through an App Cloud content feed, then load it using the SDK method bc.core.getData(). This service has multiple benefits: First, it lightens the load on the origin server (in my case, a small Wordpress site). The App Cloud server periodically fetches new data, caches it, and makes it highly available to thousands of devices. Second, App Cloud reduces the size of the payload by eliminating unnecessary data fields. Third, App Cloud converts the data from XML to JSON on the server side, flattens it, compresses it, and provides a convenient interface for accessing it.

Working with the device

PhoneGap: While I didn’t really take advantage of native device capabilities, I noticed that PhoneGap’s device API is more mature than App Cloud’s. For example, PhoneGap supports access to the contacts database and compass. It also has a nice interface for determining the device’s connection type. And the API itself is very well organized.

App Cloud: While App Cloud offered less in the way of device capabilities, there were some built-in features that I found to be invaluable. First, it’s often necessary to display external web content without forcing the user to leave the app. For this reason, the App Cloud SDK makes it extremely easy to open native modal windows. (PhoneGap has some plugins for this, but they require extra configuration.) Second, many types of content apps require multiple, distinct views. By default, App Cloud supports multiple views backed by native navigation controls. Developers can hide the navigation bar outright or toggle it via bc.device.enterFullScreen() and bc.device.exitFullScreen().

Note: App Cloud will soon release its own plugin development kit that allows developers to create custom native functionality on top of the App Cloud SDK.

Running the app

PhoneGap: From a distance, it was hard to distinguish between PhoneGap and App Cloud. But there were a couple issues with PhoneGap. First, I was unhappy with the smooth scrolling (or lack thereof) in jQuery Mobile, my chosen UI layer. I considered switching to Kendo UI Mobile, but I didn’t want to pay $199 for it. I also looked at Sencha Touch, but it was too bulky (a 55MB download). I settled on iScroll. Problem solved. Second, the part of my UI that displayed multiple images (at 150KB each) was noticeably slower to load.

App Cloud: I cheated here and used App Cloud’s image transcoding API, even though it’s not part of the free edition (App Cloud Core). I cropped and scaled each thumbnail image on the fly, shaving nearly 1MB off the total payload and speeding up the rendering of the UI. Sure, I could have cut up these images by hand, but that’s simply not practical to do when delivering dynamic images to multiple platforms across many types of devices.

I also saved a few cycles by loading my data through an App Cloud content feed. Not only was the payload smaller, I didn’t need to convert it from XML to JSON on the client.

App Cloud’s smooth scrolling was also faster than iScroll when handling complex content.

One final note on performance: Both apps ran faster on iOS than on Android.

Building the app

PhoneGap: Since I had already done the hard work of setting up XCode and the Android Developer Tools, building the app for production was relatively straightforward. I just repeated what I had already done a dozen times during development (although I added my own icons and loading images).

App Cloud: I zipped up the directory containing my static assets—HTML, CSS, JS, etc.—and uploaded it to App Cloud Studio. Then I clicked “Publish App” and was asked to enter tons of provisioning information for iOS and Android. Although tedious, this process was certainly easier than having to build the apps myself, and at the end I was able to download an IPA file for iOS and an APK file for Android.

And the winner is …

I think PhoneGap and App Cloud are both winners, but in different categories. PhoneGap wins for having a more robust device API, great documentation and examples, and a large ecosystem of plugins. (As I mentioned above, App Cloud is about to release its own plugin framework, and it will support many PhoneGap plugins.) App Cloud wins for its elegant development model—the Workshop app is simply unmatched—and for its array of cloud services.

The biggest distinction is this: While PhoneGap is a development platform, App Cloud is a development platform and an operational platform at the same time. In my simple demo app, I took advantage of two App Cloud services: image transcoding and content feed optimization. I also compiled my iOS and Android apps in the cloud from a single code base. In a more complex app, I would use App Cloud’s push notification API, real-time analytics, and remote configuration capabilities. Sure, these things are possible with PhoneGap, but not without cobbling together lots of moving parts from many different vendors.

I encourage web developers who are exploring hybrid-native solutions to evaluable both platforms as I have. You might find PhoneGap to be exactly what you’re looking for: a cross-platform development kit. But if you need more in the way of services (image transcoding, content optimization, push notifications, etc.) and less in the way of heavy toolchains (XCode and Eclipse), take App Cloud for a spin.

Both App Cloud and PhoneGap have a lot to offer. I hope they continue to push each other—and web developers—forward.

Opening a Modal Email Window in App Cloud

The latest version of the App Cloud SDK (1.12) introduces a new device method for launching a modal email window inside an app. (Previously, the only way to launch a native email client was through a “mailto” link, which bounced users out of the app. Boo.) Here’s how to do it:

// all properties optional
var options = {
    toRecipients: ",",
    subject: "Check it out!",
    body: "I found this interesting:"

// fired when the email is sent
var successCallback = function () {
    // yay!

// fired if the user cancels
var errorCallback = function (error) {
    // boo!

// open the modal
bc.device.modalEmail.composeEmail(successCallback, errorCallback, options);

Of course, in your own code you’d have to pass some real data into the options object. Check out the API docs for a full rundown.

Monitoring the Connection State in App Cloud

The latest version of the App Cloud SDK (1.11) introduces a new type of event for monitoring whether the user is online or offline. It’s a snap to use:

$(bc).on("connectionstatechange", function(evt, data) {
    if ( {
        // do something
    else {
        // do something else

Now you can take appropriate action when a user’s connection goes in or out. For example, say you want to show a status indicator:

function displayStatusIndicator(online) {
    // show or hide the indicator

$(bc).on("connectionstatechange", function(evt, data) {

Sometimes it’s necessary to check the connection status before performing a particular action. For this you can look to the bc.context object:

$(bc).on("init", function (evt) {
    if ( {
    else {

Together, the connectionstatechange event and property can help you handle network failures gracefully.

Markup.js: Custom Pipes for Your Piping Pleasure

While Markup.js comes with more than 40 built-in pipes for everyday use, I always write a few custom pipes whenever I build an App Cloud app. Here are some of my favorites.


Use this pipe to highlight a search term or other pattern in a string. Note the use of backticks in the example to denote a context variable on the right side of the expression.

// Example: {{article|highlight>`searchTerm`}}

Mark.pipes.highlight = function (str, pattern) {
    return str.replace(new RegExp("(" + pattern + ")", "g"), "<em>$1</em>");


Use this pipe to wrap an address in a Google Maps link.

// Example: {{home_addr|address}}

Mark.pipes.address = function (addr) {
    return "<a href=\"" + encodeURI(addr) + ">" + addr + "</a>";


Use this pipe to convert all URLs in a string to links.

// Example: {{story|links}}

Mark.pipes.links = function (str) {
    return str.replace(/\b(https?:[^\b\s]+)\b/g, "<a href=\"$1\">$1</a>");


Use this pipe to repeat a string. Note count defaults to 2 and separator defaults to “”.

// Example: {{chorus|repeat>5}}

Mark.pipes.repeat = function (str, count, separator) {
    return new Array(+count || 2).join(str + (separator || "")) + str;


Use this pipe to format a date with Moment.js.

// Example: {{created_at|moment>M/D/YYYY}}

Mark.pipes.moment = function (date, format) {
    return moment(new Date(+date || date)).format(format);


Use this pipe to format a number in dollars with Accounting.js.

// Example: {{price|dollars}}

Mark.pipes.dollars = function (num) {
    return accounting.formatMoney(+num);


Use this pipe to format a U.S. phone number.

// Example: {{mobile_phone|phone}} = function (str) {
    var s = str.replace(/[^\d]/g, "");
    return "(" + s.substr(0, 3) + ") " + s.substr(3, 3) + "-" + s.substr(6, 4);


Use this pipe to express a number as an ordinal, e.g. “10th”.

// Example: {{contestant.standing|ordinal}}

Mark.pipes.ordinal = function (num) {
    if (num > 10 && num < 20) {
        return num + "th";
    return num + ["th","st","nd","rd","th","th","th","th","th","th"][num % 10];


Use this pipe to express a number in stopwatch notation (“mm:ss”) given a factor of 1 (seconds) or 1000 (milliseconds). Note factor defaults to 1.

// Example: {{duration|runtime}}

Mark.pipes.runtime = function (time, factor) {
    var m = Math.floor(time / (60 * (factor || 1)));
    var s = Math.floor((time / (factor || 1)) % 60);
    return m + ":" + ("00" + s).substr(-2);


Use this pipe to determine if an array contains an object with the given property value.

// Example: {{if fruits|has>color>red}} ... {{/if}}

Mark.pipes.has = function (arr, prop, val) {
    return arr.some(function (item) {
        return item[prop] == val;


Use this pipe to filter an array of objects to only those having the given property value.

// Example: <ul> {{fruits|sift>color>red}} <li>{{}}</li> {{/fruits}} </ul>

Mark.pipes.sift = function (arr, prop, val) {
    return arr.filter(function (item) {
        return item[prop] == val;


Use this pipe to print star and half-star characters given a decimal input. Note this requires Font Awesome.

// Example: {{rating|stars}}

Mark.pipes.stars = function (rating) {
    var n = Math.round(+rating * 2) / 2;

    return new Array(Math.floor(n) + 1).join("&#xf005;") + (n % 1 ? "&#xf089;" : "");

Get more pipes in the Markup.js repository on GitHub.

App Cloud and Kinvey: A One-two Punch for Content-centric, Data-driven Apps

For many developers, App Cloud is a one-stop shop for all their application needs. It’s got a robust SDK and a sweet suite of runtime cloud services like image transcoding, data feed optimization, and cross-platform push notifications. But no platform can do everything. While App Cloud is primarily concerned with delivering content to apps, services like Kinvey can help you manage the river of data that users might generate from inside those apps.

Kinvey is remarkably easy to use. In just a few minutes, I created an account, set up an “app” in the Kinvey console, created a “collection” of friends, and started populating the collection from a few lines of JavaScript in my App Cloud app.

Kinvey Console

Adding a friend to my “friends” collection was a snap:

function saveFriend(firstName, lastName) {
    var entity = new Kinvey.Entity({
        firstName: firstName,
        lastName: lastName
    }, "friends");{
        success: function(friend) {
        error: function(err) {

Querying the collection was just as straightforward:

function findFriendsByLastName(lastName) {
    var query = new Kinvey.Query();

    var collection = new Kinvey.Collection("friends");

        success: function (list) {
            list.forEach(function (item) {
                console.log(item.attr.firstName, item.attr.lastName);
        error: function (err) {

It was also a cinch to create new user accounts for permissioning purposes:

var user = {
    username: "AdamBomb",
    password: "k@b00m!",
    name: "Adam Mark"

    success: function(user) {
    error: function(err) {

Together, App Cloud and Kinvey are a one-two punch for making high-performing, cross-platform apps backed by powerful content and data services. To make it easy for developers to get started with both platforms, App Cloud and Kinvey collaborated on a simple demo app that shows how to create users and store user data in the cloud.

Want to dive deeper? Check out the Kinvey JavaScript Developer’s Guide and the Quick Start to App Cloud.

Getting to the Promised Land of Cross-platform, Device-independent Displays

I’ve been leaning heavily on CSS Media Queries and Flexbox to build App Cloud apps that adapt to both portrait and landscape modes. For example, I made a video playlist that flows from top to bottom in portrait mode and left to right in landscape mode:

Portrait and landscape orientations

I also use CSS to build “universal” apps that adapt intelligently to different form factors. The properties min-device-width and max-device-width can help detect whether an app is running on something the size of a phone or something the size of a tablet. Smashing Magazine has a good tutorial on this subject.

But CSS alone can’t get me to the promised land of cross-platform, device-independent displays. Here’s where it comes up short:

  • CSS can’t change the behavior of an app. It can only affect presentation characteristics. Except for toggling the visiblity of certain page elements or adjusting their metrics, it’s nearly impossible to apply device-specific or orientation-based functionality without the help of JavaScript.

  • CSS can’t resize images. Yeah, you heard me. CSS can scale down an image, but it can’t resize an image. A 250KB image is still 250KB whether you display it at 100% or 50% of its intrinsic size. To properly scale images for all kinds of devices, you’ll need the help of a transcoding service.

Getting to the promised land—we’re talking about apps that adapt to portrait and landscape modes and work across a variety of devices and perform really well—is easy with App Cloud. Here’s how.

Responding to orientation changes

If you know the current orientation—and if you know when it changes—you can make intelligent decisions about the user experience. For example, you might want to load some extra data or transform the UI entirely when the user switches into landscape mode:

// get the current orientation ("landscape" or "portrait")
var orientation = bc.context.viewOrientation;

// listen for an orientation change
$(bc).on("vieworientationchange", function (evt, result) {
    orientation = result.orientation;

    if (result.orientation === "landscape") {
        // do something!
    else {
        // do something else!

Distinguishing between phones and tablets

If you know whether your app is running on a phone or tablet, you can deliver specific functionality to each form factor from a single codebase. For example, here’s a factory method that instantiates one type of BlogView if running on a phone, another if running on a tablet:

BlogView.factory = function () {
    return getDeviceType() === "phone" ? new PhoneBlogView() : new TabletBlogView();

There are a few ways to determine the device type. A simple method is to look at the width and height of the window, multiply them together, and evaluate the result:

function getDeviceType() {
    return innerWidth * innerHeight <= 320 * 480 ? "phone" : "tablet";

Here’s a similar technique from

function getDeviceType() {
    return window.matchMedia("(max-width: 650px)").matches ? "phone" : "tablet";

These methods are great if your definition of a phone is somewhat fast and loose (some Android phones are as big as tablets). Instead, consider categorizing your target devices as “big” and “small”:

function getDeviceType() {
    return window.matchMedia("(max-width: 650px)").matches ? "small" : "big";

Distinguishing between operating systems

Sometimes it’s necessary to know which operating system you’re running on. App Cloud makes this easy:

var os = bc.context.os;

if (os === "ios") {
    // do something
} else if (os === "android") {
    // do something else

In the above example, “doing something” might mean loading different stylesheets or disabling a certain feature that isn’t available on Android.

Resizing images

The pièce de résistance of responsive design is being able to resize and crop images on the fly based on runtime conditions such as screen size and pixel density. You can do this with App Cloud’s image transcoding API.

Before and after images

It’s easy to use JavaScript to compose service URLs based on screen metrics or other layout constraints. Here’s a simple example:

function transcode(src, width, height) {
    return "" + src +
        "&width=" + width + "&height=" + height;

If you want to support retina displays, just double the width and height if window.devicePixelRatio equals 2:

function transcode(src, width, height) {
    if (window.devicePixelRatio === 2) {
        width *= 2;
        height *= 2;

    return "" + src +
        "&width=" + width + "&height=" + height;

Retina images are typically four times as big as normal images (double the width times double the height), so consider using a multiplier between 1 and 2 to lighten the load a bit while still improving quality.

You can also crop images with the image transcoding API rather than rely on CSS tricks. Remember, every bit counts in a mobile app. Load only what you need when you need it.

Learn more

You can see all of these techniques at work in the App Cloud Demos repo on GitHub. The promised land is closer than you think!

Launching External Apps in App Cloud

Sometimes it’s necessary to launch an external app from within your own app. After all, your app can’t do everything! In App Cloud, it’s easy to do with the device method bc.device.openURI().

Say you want to open an external web browser whenever a user taps a button:

$("#exampleButton").on("tap", function (evt) {
    // both callback functions are optional
    bc.device.openURI("", onSuccess, onError);

Easy enough! But what if you have many buttons, each leading to a different URI? Consider embedding each URI in a data attribute:

<button data-href="">Open me</button>
<button data-href="">Me too!</button>

Then you can listen for a tap event on any element having a “data-href” attribute and extract the URI from that element:

$("[data-href]").on("tap", function (evt) {
    var uri = this.getAttribute("data-href");
    bc.device.openURI(uri, onSuccess, onError);

Special cases

In some cases, iOS uses specific apps to handle special types of URLs. For example, any URL beginning with “” opens in the Maps app:

iOS screen shot

Android may present the user with several options in order to determine the “intent” of the action:

Android screen shot

Using modal windows

If you’re simply opening a web page, you might want to open it modally instead of bouncing the user out of your app. Just set “modalWebBrowser” to true in the device call:

bc.device.openURI(url, onSuccess, onError, { modalWebBrowser: true });

You can also use links to accomplish the same thing without JavaScript:

<a href="">For example ...</a>

Inside the App Cloud Workshop: Understanding Your Apps in Development Mode

The App Cloud Workshop app for iOS and Android is an amazing tool for app developers. It lets you preview your apps in the palm of your hand without the need for complex toolchains like XCode or the Android Developer Tools, and it mimics the web development workflow: Code, Refresh, Repeat.

App Cloud Workshop

But there are some subtle differences between how an App Cloud app behaves in development mode and how it behaves in production mode as a compiled binary. Here’s what you should keep in mind:

  • Your app will load a bit more slowly in development mode because all of its assets—HTML files, scripts, stylesheets, images, etc.—are fetched from an external server. In a compiled app, most or all of these assets will be baked into the binary package and loaded from disk.

  • In development mode, your app will open without a launch icon or splash screen. These assets are added during the publishing process. When a user opens your published app, they’ll see the launch screen for a few seconds as the app loads.

  • You might see a blank white screen in the Workshop as you load and refresh each View. In a compiled app, you might only see this happen if a View is “torn down” by the app container in order to reclaim memory, or if your app has Views that live deep inside the “More …” menu.

  • In the Workshop, a developer can refresh individual Views and even restart an app when it behaves poorly or strangely, but these options aren’t available to users in a published app. (Developers should “stress test” their finished apps for extended periods of time in order to identify issues that might only surface after heavy use.)

  • Some device functions behave differently in the Workshop. For example, when downloading a file with the File Download API, the downloaded file is inaccessible in the Workshop. This particular quirk and others are explained in the App Cloud API docs.

  • A few App Cloud services don’t work in development mode, including push notifications and analytics.

The only way to truly test the behavior of your finished app is to publish it and install it on your device before deploying it to the app stores. On iOS, you can create a development certificate or ad hoc certificate for this purpose. On Android, you can side-load your app onto a phone or tablet.

When used properly and in tandem with rigorous testing practices, the Workshop is an invaluable part of the App Cloud experience. Pretty soon you’ll wonder how you ever got by without it!

A Font of Icons for Your App Cloud App

I recently came across an awesome web font called Font Awesome. How appropriate! Each character in the font is a graphical icon instead of a number of letter. Here’s what it looks like in my App Cloud demo app (I’ve circled each use):

Screen shots

There are a ton of great icon fonts that you can drop into your App Cloud app without much fuss—just be sure the font is a TTF font so it can work on both iOS and Android. Not only will you save a ton of time in the design stages, these icons will look great at any size and resolution. Just adjust the font-size property in your CSS!