Monday, January 21, 2013

Integrating your web application with Ubuntu Unity

Starting with version 12.04, Ubuntu has been adding some nifty features that let developers integrate web applications with the desktop.  This makes web applications work similarly to native applications -- icons on the Launcher, nice volume control, desktop notifications, messaging system integration, the whole works.  It's really cool, but not used as widely as I'd like.  So I put together a little sample application to show how easy it is to do!

The API is easy to use, and anyone who is writing a web app should be able to use it.  Basically you just need to make a few simple Javascript calls and your web app will integrate nicely with Ubuntu.  I did come across a few 'gotchas' on the way though, so I'll point those out as well.

Javascript callbacks


A bit of background information is in order here.  Javascript functions are themselves just another type of javascript object, meaning that you can do things like set them as the value of a variable or pass them to a function just like any other piece of data.  There's a good article about this here but you don't need to know all the details to integrate your web app with Unity.  Really all you need to understand is that some of the bits of the integration expect you to pass them a function object, not just a string of code.  (Try to pass in code where a callback is expected and you'll just end up executing that code when the page loads... probably not what you want to happen!)

An example callback:


Unity.Launcher.addAction("Messages",
function(){ unityRedirect("messages");
);


The second parameter passed to addAction() here (which I've highlighted in yellow) is itself a function, making it a callback for addAction().

Basically all you need to remember is that if you want to call code to make something happen in your web app, you need to pass a function in rather than just the code you want to execute.

Getting set up and adding a launcher icon

Before you can do anything fancy, you need to have some sort of way of getting information from the browser to Unity.  Fortunately, there's code in Ubuntu to do this already.  All you need to do is call it:

var Unity = external.getUnityObject(1.0);

This will set up the Unity integration object.  It expects to be told what version of the API to use.  Currently the latest (and only) version is 1.0, so that's what your code should use too.

Now that you have a way to talk to Unity, you need to tell it a bit about your app.  That's done through the Unity.init() method:


Unity.init({
name: "Example Web App",
iconUrl: "http://www.example.com/icon.png",
onInit: unityReady
});


The parameters to init() are pretty straightforward:
  • name - the name of your application
  • iconUrl - a URL pointing to an icon for your application (which should be of reasonable size; don't use your favicon as it will be scaled up and look really ugly!)
  • onInit - a function to call when everything is loaded and ready

Here's one of those gotchas I mentioned earlier: it's really important to keep everything you need to tell Unity to do initially inside of the function you set as your onInit!  The Unity.init() method runs asynchronously -- just because execution has passed to the next line in your code doesn't mean that the Unity object is ready to use!  So don't try something like:


Unity.init({
...
});
Unity.Launcher.addAction(...); // No!  Don't do this!


Doing this is almost certainly going to fail and cause you lots of frustration.  Always do your integration setup inside of your onInit function.

Once you've set up the Unity object, your application will automatically get an icon in the Dash (and on the Launcher when it's running or pinned there).

Our little web app is growing up!  It's just like a desktop application now.

Going beyond the basics: adding functionality Launcher icon

Now that you have an icon in the Launcher, you can make it useful to the user  by adding quicklinks.  These are a menu in your icon that give the user a fast way to jump to different parts of your web application.

Remember the function you passed as the onInit parameter to init() earlier?  This is where it comes in handy.


function unityReady() {
Unity.Launcher.addAction("Messages",
function(){ unityRedirect("messages"); } 
);
}


This will add a quicklink to a page on your site called "messages".

Another gotcha: unfortunately, the quicklink functionality for web applications appears to be broken right now in Ubuntu 12.10.  Even the default applications that are integrated with Unity by default don't work.  Hopefully this will be fixed in the near future!

There's more you can do with the Launcher icon too.  For example, you might want to show the user that they have some unread messages on your site by adding a count to the icon, like this:

Unity.Launcher.setCount(4);

I have 4, um, examples

You can also set a progress bar with Launcher.setProgress().  There's more information about that in the API reference.

Getting more advanced: indicator integration

There's another way of showing how many messages a user has that helps them access their messages faster and is more consistent with the rest of the Unity desktop: the Messaging Indicator.  Fortunately it's easy to integrate with it as well!


Unity.MessagingIndicator.showIndicator(
"Inbox", {
count: 3, 
callback: function(){ unityRedirect("messages"); }
});


The above code will add a new entry to the Messaging Indicator with your application's icon and the title "Inbox".  When the user clicks on it, the callback you specify will be called.  (You probably want to direct the user to the appropriate place on your web application to view or reply to these messages here.)

I should check my messages more often


Finally, why not let the user know when they have received a new message?  You can do that with a desktop notification:


Unity.Notification.showNotification(
"Example Application", // message header
"This is your notification!", // message body
false);


This gives a standard desktop notification to the user with your application's icon.



Another gotcha: The API documentation says that the third parameter to showNotification() (which would be a URL pointing to a custom icon) is optional, but it's really not.  If you don't put something there, your notification won't be shown.  I've used false in my example, which seems to work well.

Now you're ready to get started on your own application!  There's more functionality available that I didn't go over here (such as Media Indicator integration for web apps with multimedia functionality and some optional features of Unity and Launcher integration), so I'd recommend checking out the API documentation as well.  Finally, my example code is available as a complete unit with tons of comments on github.

Go get integrating and have fun!