DEVELOPERS BLOG

Hybrid Apps for BlackBerry 10: An introduction

Hybrid_Post

BlackBerry 10 is leading the mobile space with its browser, receiving a near 500 score on HTML5Test and supporting cutting edge features unavailable on many other mobile platforms. This makes HTML5 a very attractive development option, and has opened the doors to combining the power of Web and Native into hybrid apps. Hybrid apps combine the versatility of HTML5 with deep integration and high frame-rates of Native Cascades apps.

There are many reasons for choosing to develop a hybrid app; personally, I find HTML5 makes it easy to work with Service APIs and display fetched content, as well as working with AJAX and JSON. On the other hand, Cascades provides the signature BlackBerry 10 Experience, boasting 60 FPS animations, deep integration with the OS and a solid set of tools for development, deployment and debugging.

This guide is tailored for both HTML5 developers who are getting started with Hybrid apps as well as Cascades developers exploring and extending their tools using the WebView component. We’ll cover setup, communication and debugging, as well as creating custom QML components that rely on a WebView.

Setup

A hybrid app contains a WebView that points to a HTML page bundled with the app, typically within the assets folder (the HTML content can be bundled remotely as well).

Here is a sample structure of a hybrid project’s assets folder:

assets/
    main.qml
    web/
        index.html

Here’s the WebView definition:

//file: main.qml
WebView {
    url: "local:///assets/web/index.html"
    id: webView
}

Communication

Communication between cascades and WebView contents is done by posting messages which is similar to communicating with Web Workers, iframes and child windows in HTML5.

//file: main.qml
webView.postMessage("hello");
//file: index.html
navigator.cascades.postMessage("hi");

Receiving messages is done by using the onMessage() and onMessageReceived() handlers in HTML5 and Cascades respectively.

//file: main.qml
WebView {
    url: "local:///assets/web/index.html"
    id: webView
    onMessageReceived: function(){
        console.log(message); //outputs "hi"
    }
}
//file: index.html
navigator.cascades.onMessage(function(message){
    console.log(message); //outputs "hello"
});

Aside from passing strings, developers may pass JSON objects, which need to be serialized and deserialized as the communication is strictly using strings.

//file: index.html
var contact = {
    name: "Bob"
    age: 34
}
//JSON.stringify will serialize the object into a string
navigator.cascades.postMessage(JSON.stringify(contact));
//JSON.parse will deserialize the string into an object, so we can access its members
navigator.cascades.onMessage(message){
    var contact = JSON.parse(message);
    console.log(contact.name); //outputs Bob
    console.log(contact.age); //outputs 34
}
//file: main.qml
WebView {
    url: "local:///assets/web/index.html"
    id: webView
    onMessageReceived: function(){
        console.log(message); //outputs "[ object object ]"
        var contact = JSON.Parse(message);
        console.log(contact.name); //outputs "Bob"
        //let's add a property and send back to WebView
        contact.added = true;
        webView.postMessage(JSON.stringify(contact));
    }
}

window.onload

HTML5 developers are accustomed to listening to window’s onload() function before initializing the application. This ensures the document has loaded before we interact with it.

//file: index.html
window.onload = function(){
    App.init();
}

Here’s a trick that ensures your content is loaded and ready before you communicate with it from Cascades. Using the window.onload listener and postMessage(), Cascades can be notified when the WebView is ready to receive messages.

//file: index.html
 window.onload = function(){
     navigator.cascades.postMessage("ready");
 }

In Cascades, you can wait for the “ready” message before posting messages to the WebView:

//file: main.qml
WebView {
    url: "local:///assets/web/index.html"
    id: webView
    onMessageReceived: function(){
        if(message === "ready")
            webView.postMessage("hi WebView!");
    }
}

Debugging

Debugging WebViews is easy thanks to Remote Web Inspector. To enabled Web Inspector, add

 settings.webInspectorEnabled : true

to the WebView

WebView {
    settings.webInspectorEnabled: true
}

A BlackBerry device connected to a computer and in development mode is assigned an IP address of 169.254.0.1. At the same time, the host computer is assigned 169.254.0.2. Web Inspector listens on port 1337 and above, so

 169.254.0.1:1337

in Google Chrome while connected to the device and app open, should display Web Inspector.

Some things to note:

  • To find out your development IP address, go to Settings > Security and Privacy > Development Mode. The port remains the same: 1337.
  • Each WebView in your Cascades application will have a separate page in Web Inspector.

Web Inspector is a great tool for debugging of Web Applications. Get more information by visting “Debugging using Web Inspector.”

Live editing

Aside from debugging, Web Inspector can also be used to make live changes to the applications, which avoids repackaging and deploying the Cascades App.

This set-up requires a simple Web Server to be running on the computer. (XAMPP, etc).

  • Once the server is up, copy the HTML5 contents from assets into a folder in the directory that holds files to be served. (In XAMPP, default directory is c:XAMPPhtdocs).
  • Using a browser on the computer, navigate to
169.254.0.2/path/to/index.html
  • This should display the contents of your WebView. (If it does not, check server configuration and location of index.html and other HTML5 files).
  • Edit the WebView to point to this URL, instead of a local resource:
//file: main.qml
WebView {
    //url: "local:///assets/web/index.html"
    url: "http://169.254.0.2/path/to/index.html"
}
  • Package and deploy application
  • Load up Remote Web Inspector on the computer
  • Switch to the “Console” tab.

At this point, hitting CTRL + R (or typing in window.location.reload()) will refresh the WebView (aka reload its resources from the server). This way, any changes you’ve made to the WebView content will be reflected without re-packaging and deploying the app. That’s 30 seconds every dozen minutes saved.

Once you are satisfied with the WebView, don’t forget to copy the assets back and point the WebView back to the local resources. I prefer to comment and uncomment these as needed.

//file: main.qml
WebView {
    url: "local:///assets/web/index.html"
    //url: "http://169.254.0.2/path/to/index.html"
}

For more information on Cascades WebView, visit our WebView page.

About anzorb