HTML5: Web intents to share information between web apps

If you've read any of my other articles you're probably aware that I really like this whole "browser as the platform" concept. We can easily communicate with backend services using web sockets, parallelize javascript with web workers and access a lot of device capabilities such as web camera, battery and most of the acceleration and location sensors. One of the things, though, that was missing, was a way to easily share information between web apps.

Most web applications such as twitter, dropbox, facebook, google+ have their own custom APIs, and if you want to share information with these web applications, or make use of the services they provide (e.g. store a document in dropbox) you have to use those APIs. The share button used on this site for instance makes use of all the services specific APIs to share information. If one of the interfaces should change, a new version must be created. On android there is something called intents, which is a standard way of apps to share information that avoids all these problems.

2012-06-15_07-48-34.jpg

Instead of requiring tight integration the application that wants to share something just asks the system which apps can fulfill the request. The system returns with a list of apps the user can select and that's it. The data is sent exchanged between the apps, without requiring custom integration.

Wouldn't it be nice if we could have something like that for web apps? No more need to support 30+ different bookmarking sites, 20+ social networks and 15+ picture websites. Just one simple way to exchange information in a standard manner. Well, we can. Or better said, we'll be able to do this soon across browsers. Web intents is a new W3C specification proposed by google, to bring the goodness of Android intents to web applications.

Google Chrome.png

In this tutorial I'll show you an example how to do this. I've also put the demo online here if you want to test for yourself. Before this will work however, you need to add a chrome extension that registers for this intent (more information in the rest of the article). If you download, extract and install this archive in chrome the example will work. How to do this is shown at the end of this article.

SInce this is still a very early draft there isn't much support yet amongst the various browsers. The spec was drafted by Google, so as you can expect Google chrome at least has support for this specification (I've tested this with version 21.0.1163.0 dev). In this example we'll take the following steps:

  1. Make a (very simple) website that shows a set of links you can share (Reddit, Digg or Dzone like)
  2. Create a link sharing service that forwards this link to twitter
  3. Add this service to chrome, so that it can be shown in the chrome "intents" user interface

But first we look at the website that wants to share information with other websites.

Make a (very simple) website that shows a set of links you can share (Reddit, Digg or Dzone like)

This is just a very simple static site, that lists a set of links. At the end of each link is a share button that the users can use to share this link using any of the configured web applications. This (very ugly) site looks like this:

Service consumer-1.png

Nothing to complex, just a simple list of links with a share button. This share button is where it gets interesting. Lets look at this button, and the associated javascript.

<li>
 <p>
  <a href="http://www.smartjava.org/content/html5-access-battery-status-through-javascript">HTML5: Access Battery status through javascript</a> 
  <img class="share" src="assets/share-this-icon.png" alt="share" height="20">
 </p>
</li>
 
...
 
<script type="text/javascript">
 
    // whenever the share button is clicked
    $(".share").click(function() {
 
        // get the information we want to share, the url
        var linkToShare = $(this).prev().attr('href');
 
        // next we can define the webintent,
        var params = {
            'action': 'http://webintents.org/share',
            'type': 'text/uri-list',
            'data': linkToShare
        };
 
        // create the intent
        var intent = new WebKitIntent(params);
 
        // start the intent, and pass in the callback
        // that is called on succes.
        window.navigator.webkitStartActivity(intent, function(data) {
            $("#callback").text("Received from invoked intent: " + data);
        });
    });
</script>

As you can see, the button is just an image. We use jQuery to add an onClick listener. This onClick function is where we create the intent that we want to start. In this case it's the share intent, and as the data we provide the url of the link. There are many more intents available, and you're free to use your own. It's however a good idea to use those from webintents.org, since those are standard and used by many other applications.
In this small code fragment we also add a callback when the intent as successful. In this example we just show the result in the grey box at the bottom.
This is all you have to do at the client side. Just specify the type of intent you want, and let the platform handle the rest.

Create a link sharing service that forwards this link to twitter

The other side of web intents are services that can handle these intents. In this example we create a simple service that forwards the URL to twitter to be shared.

Service provider.png

We'll only look at the javascript, since the rest isn't really interesting.

    var intent = window.webkitIntent;
 
    var urlToShare = intent.data;
    var twitterURL = "http://twitter.com/intent/tweet"
                     + "?via=josdirksen"
                     + "&text=Look at this! - " + urlToShare + " - Shared using web intents demo from http://www.smartjava.org";
 
    // set the correct link on the url
    $("#twitterlink").attr("href", twitterURL);
 
    // register twitter callback
    $.getScript("http://platform.twitter.com/widgets.js", function () {
        function handleTweetEvent(event) {
            // this event is called when the tweet has been sent.
            // this means we can send the result back to the client.
            intent.postResult("Link successfully sent to twitter!");
        }
 
        twttr.events.bind('tweet', handleTweetEvent);
    });
 
    $("#faketwitter").click(function() {
        intent.postResult("Link successfully faked to twitter!");
    });

Here you can see that we create an url based on the data from the intent. From our client we sent an url, which we use to create an URL that we can use to directly post to twitter. After we've created the twitter url, we register the callback from twitter. So as soon as the tweet is sent, the callback is called, and we can pass the result back to our client.

Post a Tweet on Twitter.png

I also added a fake twitter link, for those of you who want to test the scenario, but don't want to actually post anything on twitter :)

So far we created our client, and a service. But how does chrome now of the existence of our service? What chrome does now is that it checks whether there are services registered in the chrome store that can handle the intent from our client, and it checks whether extensions are installed that can handle the intent. Since we don't want to submit apps to the store just to test web intents, we'll create a simple extension that we install locally.

Add this service to chrome, so that it can be shown in the chrome "intents" user interface

To create a minimal chrome extension we need an icon (that is shown in the application tab) and we need a manifest.json that describes what the extension does, and what intents it can service. The one I used is shown here:

{
    "name":"Smartjava Twitter share",
    "version":"4",
    "icons":{
        "128":"share-this-icon.png"
    },
    "app":{
        "urls":[
            "http://www.smartjava.org"
        ],
        "launch":{
            "web_url":"http://www.smartjava.org"
        }
    },
    "manifest_version":3,
    "intents":{
        "http://webintents.org/share":[
            {
                "type":["text/uri-list"],
                "href":"http://www.smartjava.org/examples/webintents/provider",
                "disposition":"window",
                "title":"Share this with twitter"
            }
        ]
    }
}

I won't go into the details of the manifest, since there are many articles that explain how to write chrome extensions. What is interesting here is that we can now add an "intents" element. This element specifies the type of intent we're interested in. So with this configuration we tell the platform that we can process "http://webintents.org/share" intents and know how to handle text/uri-list types. When we receive such an intent we open the supplied href, which points to the web application we discussed earlier.

Now all we need to do is register this in your browser. You can simply do this by using the "load unpacked extension..." functionality from chrome (in developers mode):

Extensions.png

And that's it. We can now use the chrome web intents functionality to share information just like we do on android devices.

Service consumer-2.png