Adam Mark

Web design and development

Digging Deeper Into App Cloud Data Feeds

Smart Content Sources are a quick and easy way to load data into your App Cloud apps. Let’s take a look at what happens under the hood when you load a content source with bc.core.getData():

Screen shot

First, no matter what kind of data you’re loading from App Cloud—a Video Cloud playlist, a content feed, or a text block—you can call it the same way in your code:

bc.core.getData("1234567890", handleData, handleError);

Above, “1234567890” is the ID provided by App Cloud Studio. You can also declare the feed in your manifest file and call it by name:

bc.core.getData("blog", handleData, handleError);

The function getData() is asynchronous. When it runs successfully, the SDK calls handleData; otherwise, it calls handleError. The success handler takes a single argument:

function handleData(data) {
    console.log(data);
}

If you log the data to the console, as shown above, you might see an object like this one, which comes from a Video Cloud playlist:

Screen shot

So what’s happening under the hood?

The App Cloud SDK injects a <script> tag into the document and sets the src attribute to the URL of a content feed:

<script src="http://read.appcloud.brightcove.com/content/50019dfcec8e60277d00fdb8/
fetch?callback=jQuery17207518197379540652_1343651580663&_=1343651580663"></script>

This process has the curious name JSON-P, or “JSON with padding.” Notice the URL contains the name of a callback function to execute when the script is loaded.

When the script is loaded, it executes a function that wraps (or “pads”) a JSON object. Here’s what it looks like inside the Network panel of the Chrome Developer Tools:

Screen shot

This function, in turn, hands off the data to the callback function specified in bc.core.getData().

As you can see, it’s easy to inspect your data using the Chrome Developer Tools. And if you want to dig even deeper, consider using an HTTP monitor like Charles.

Finally, keep in mind that bc.core.getData() is just one way to load data into your app. You can also use the device functions fetchContentsOfURL(), postDataToURL(), and requestDownload().

Bug Off! App Cloud Introduces On-device Debugging

Bugs are a way of life in both the physical and virtual worlds. In the physical world, we can “debug” with fly swatters and bug spray. In the virtual world, debugging is a bit more sophisticated, as software bugs can be invisible and unpredictable.

It’s doubly hard to identify and kill bugs running on a mobile device—unless you have the right tools. App Cloud developers already have the Workshop app for previewing and interacting with their work in real time. Now they can take advantage of on-device debugging—also called remote debugging—to remotely inspect and tune their code. Here’s how it works:

First, go to the “On-Device Debugging” page in App Cloud Studio. Then open an app in the Workshop and give the device a good shake. When the camera launches, scan the QR code that appears in the Studio:

Screen shot

Once a connection is established, you’ll see a debug panel in the Studio that looks like the Chrome Developer Tools. From here, you can remotely inspect and modify the DOM, issue JavaScript commands, and more:

Screen shot

As a test, click the “Console” tab and type bc.device.alert("Whoa!"). You’ll see an alert pop up on the device!

App Cloud’s on-device debugging is based on the open source Weinre project. It’s a great tool for developers who want to build rock-solid apps quickly and easily.

Get the Download on App Cloud’s File Download API

Your content-centric app is only as good as the network it’s running on—until now. With App Cloud’s File Download API, you can permanently store all kinds of media assets on the device for offline use. Text feeds, images, PDF documents, audio and video files, you name it. This presents lots of possibilities for app developers:

  • Your apps can degrade gracefully when the user’s network goes in and out

  • You can program your apps to front-load content so they work perfectly in “airplane mode”

  • You can allow users to create custom content experiences that work anywhere, anytime

Of course, your app can do all of the above. Here’s a quick look at the methods and events in the File Download API:

Methods

  • bc.device.requestDownload(): Download a file from a remote URL

  • bc.device.removeDownload(): Delete a previously downloaded file

  • bc.device.isDownloadAvailable(): Determine if the device supports file downloading

  • bc.device.getDownloadInfo(): Get information about previously downloaded files

As with other device methods, these are asynchronous—you must provide success and error callbacks.

Events

  • downloadprogress: Dispatched on each progress event at the specified interval (e.g. 5%) (iOS only)

  • downloadcomplete: Dispatched when a download finishes

  • downloaderror: Dispatched on certain error conditions

The API is low-level by design, requiring you to use bc.core.cache() to store associated metadata in most situations. I’ve written a FileManager object to hide some of the implementation details of downloading, retrieving and deleting files—check it out in the App Cloud Demos repo, then get downloading!

GET Out! How to POST Data in App Cloud

The App Cloud SDK provides two device methods for exchanging data with remote services. You’re probably familiar with the first one:

bc.device.fetchContentsOfURL(url, successCallback, errorCallback)

This method makes a cross-domain GET request, AJAX-style, to a remote URL. You might use it to pull down some tweets:

var url = "http://api.twitter.com/1/statuses/user_timeline.json?id=@adammark75";

var handleData = function (data) {
    var tweets = JSON.parse(data);

    displayTweets(tweets);
};

var handleError = function (error) {
    bc.device.alert("Oops! " + error.errorMessage);
};

bc.device.fetchContentsOfURL(url, handleData, handleError);

The second method works the same way, except it makes a POST request:

bc.device.postDataToURL(url, successCallback, errorCallback, options)

You might use it to send credentials to an authentication service:

var url = "https://example.com/login";

var options = {
    data: {
        "username": "boba",
        "password": "fett"
    }
};

var handleData = function (data) {
    var response = JSON.parse(data);

    if (response.authorized) {
        permitUser();
    }
    else {
        rejectUser(response.failureCode);
    }
};

var handleError = function (error) {
    bc.device.alert("Oops! " + error.errorMessage);
};

bc.device.postDataToURL(url, handleData, handleError, options);

With these two device methods, you can access any REST service, AJAX-style!

Try Before You Transcode: App Cloud Studio Helps You Explore Image Transcoding API

App Cloud’s real-time image transcoding API now has a public “face” in App Cloud Studio. Developers can use it to explore the API in a visual way before writing a single line of code. Just enter an image URL and set a few parameters like width, height and image quality:

Screen shot

It’s a quick way to determine the best level of compression for some JPEG photos or the correct cropping algorithm for a series of thumbnail images.

With image transcoding, developers can dramatically improve app performance by reducing image sizes by 90% or more. And it’s a snap to use—service URLs can be composed at runtime with a little bit of JavaScript.

See the App Cloud docs for a complete rundown of the API.

Using ‘on’ and ‘Off’ Events in App Cloud

The latest version of the App Cloud SDK includes jQuery 1.7, which introduces new methods for handling events.

Background

Prior to version 1.7, jQuery gave us a handful of ways to handle events. You’re probably familiar with the bind method:

$("li").bind("click", function (evt) {
    // do stuff
});

Above, we’re binding an anonymous callback function to every li element in the document. The callback function has one argument (an object) that contains all the properties of the captured event. It’s simply a shorthand for the following:

var elems = document.querySelectorAll("li");

for (var i = 0; i < elems.length; i++) {
    elems[i].addEventListener("click", function (evt) {
        // do stuff
    });
}

The jQuery version is nicer, don’t you think?

The bind method works on elements that already exist in the document. But what if the elements don’t exist yet? Enter the live method:

$("li").live("click", function (evt) {
    // do stuff
});

The live method works on matched elements now or in the future by attaching a single event listener to the document root element and then inspecting the event data to determine which specific handlers to trigger. Pretty handy. The delegate method works in a similar fashion, although you can specify a scope:

$("ul").delegate("li", "click", function (evt) {
    // do stuff
});

Each of these methods has a corresponding function to remove event listeners: bind and unbind, live and die, delegate and undelegate.

New in jQuery 1.7

In jQuery 1.7, all the above methods are replaced with on and off. There are two ways to use on:

$("#dataTable tbody tr").on("tap", function (evt) {
    // do stuff
});

$("#dataTable tbody").on("tap", "tr", function (evt) {
    // do stuff
});

The first technique is like using bind; the second technique is like using delegate and is more efficient when working with large DOM trees.

See the jQuery docs for a complete rundown.

Get Two Layouts for the Price of One With CSS Media Queries

Screen Shot

Some App Cloud developers have asked me how to change the layout of a view depending on the device’s orientation. The simplest way—and this is really very simple—is to use Media Queries:

@media all and (orientation: portrait) {
    /* CSS rules here */
}

@media all and (orientation: landscape) {
    /* CSS rules here */
}

For example, let’s say you want to change the body color from red to green when the user rotates the device from portrait to landscape:

@media all and (orientation: portrait) {
    body {
        color: red;
    }
}
@media all and (orientation: landscape) {
    body {
        color: green;
    }
}

Add the above code to your stylesheet and see what happens. (You can test it in your Webbrowser by resizing the window.)

It’s not necessary to put all your styles inside the media queries—just the styles that are specific to portrait or landscape mode.

Combine Media Queries with the Flexible Box Model and now you’re cooking with gas!

Two notes: First, you must allow for orientation changes in the SDK by calling bc.device.setAutoRotateDirections(["all"]). Second, CSS rules can only affect the layout, not the behavior, of your app. You can listen for a vieworientationchange event if you need to perform some action when the user rotates the device.

Making Better Markup With Markup.js

Unlike traditional web sites, App Cloud apps compose HTML strings in the client using JavaScript. There are two ways to go about this: a good way and a bad way.

First, the bad way. Consider the following code, in which an array of articles is manually formatted into a chunk of HTML code:

var html = "<ul>";

for (var i = articles.length - 1; i >= 0; i--) {
    html += "<li>";
    html += "<div>" + articles[i].title.toUpperCase() + "</div>";
    html += "<small>";
    html += articles[i].description.substr(0, 50);
    if (articles[i].description.length > 50) { 
        html += "...";
    }
    html += "</small>";
    html += "</li>";
}

html += "</ul>";

Notice how even simple tasks, like adding an ellipsis to descriptions longer than 50 words, can force you to write a lot of code. This gets messy fast!

Now, the good way: Take the same array of articles and generate the equivalent HTML using Markup.js:

<ul>
    {{articles|reverse}}
        <li>
            <div>{{title|upcase}}</div>
            <small>{{description|chop>50}}</small>
        </li>
    {{/articles}}
</ul>

Much nicer! As you can see, Markup.js takes the pain out of converting structured data (like an array of articles) into HTML or another text format. And since it’s part of the App Cloud SDK, you can quickly and easily separate your presentation logic from your business logic. Let’s say you’re handling the results of a data request:

function handleData(data) {
    var template = bc.templates["articles-list-template"];
    var context = { articles: data };
    var markup = Mark.up(template, context);

    document.getElementById("results").innerHTML = markup;
}

In the above code, Markup.js takes a template string, injects it with a context object, and returns a new string. The new string is then inserted into the document. There’s no HTML at all in your JavaScript code! (You could easily modify this code to select one of several templates based on a runtime condition or device characteristic.)

Notice the object bc.templates? It’s populated automatically with strings from an external text file (as defined in manifest.json):

===== hello-template
<p>Hello, <span class="username">!</span></p>

===== goodbye-template
<p>Goodbye, <span class="username">!</span></p>

In this example, the text file contains two Markup templates: hello-template and goodbye-template. You can call them by name, as shown above.

Markup.js comes with more than 40 built-in “pipes” for transforming data, and it’s easy to write your own. Check out the complete docs on GitHub.

Where in the World Is App Cloud?

The App Cloud team circled the globe twice in the last month to run developer kitchens in Seoul, Tokyo and Sydney. We trained more than 70 developers and racked up thousands of frequent flier miles to boot! Here are some shots from the events:

Seoul, South Korea

Seoul

Seoul

Tokyo, Japan

Tokyo

Tokyo

Sydney, Australia

Sydney

Three Ways to Use Text Blocks in App Cloud

With App Cloud text blocks, you can store arbitrary blocks of text in the cloud and retrieve them for any purpose you desire. Now you can bypass your CMS (and your IT department!) when you need to manage certain types of lightweight data in your apps.

To create a text block, go to the Content section of App Cloud Studio, then click “New Content Source”, then click “Text Content”:

Screen shot

Then enter a name and some text. That’s it! Whenever you want to change the text, just click “Edit” and App Cloud will save a new version. (You can revert to an old version at any time.)

At the code layer, you can request a text block with bc.core.getData(), just like a content feed:

bc.core.getData("my-text-block", function (data) {
    var myText = data.text;
    // do stuff
});

Here are three ways to use text blocks inside your app:

1. HTML text

Use a text block as a flexible messaging area:

Screen shot

Then insert the text into DOM using jQuery or the method of your choice:

bc.core.getData("welcome-message", function (data) {
    $("#welcome-message").html(data.text);
});

2. JSON text

Use a text block to store structured data in JSON format:

Screen shot

When you load the text, make sure to parse it using JSON.parse():

bc.core.getData("produce", function (data) {
    var produce = JSON.parse(data.text);
    ...
});

3. CSV text

Store a table of information as CSV:

Screen shot

After you load the data, split the lines, then split each line on the comma characters:

bc.core.getData("directory", function (data) {
    var people = [];
    var rows = data.text.trim().split("\n");

    for (var i in rows) {
        var row = rows[i].split(",");

        people.push({
            "firstName": row[0],
            "lastName": row[1],
            "phone": row[2],
            "title": row[3],
            "email": row[4]
        });
    }
});

These are just a few ways to use text blocks. As you can see, you can save any kind of text format you want—it’s flexible by design!