WebSockets and Android

I didn't know that the default browser installed on Android is called Webview. I haven't created any native Android app ever. But I wanted my web app to run on Android using Websockets. Unfortunately, websockets are not implemented in Android Webview.

In modern browsers, HTML5 provides a websocket API:

  1.  
  2. ws = new WebSocket('ws://' + host + ':'+ port);
  3. ws.onmessage = function(msg){
  4. var data = JSON.parse(msg.data);
  5. ws.send(JSON.stringify({message: 'OK cool!'}));
  6. };
  7.  

You don't need to include any JavaScript file in order for this to be valid code in modern browsers (when I saw it for the first time I was like.... "yeah cool but what library are you using?). Well you'd need a Websocket server. I've been trying ws for Node. It works very well with express.js and is very simple:

  1.  
  2. var WebSocketServer = require('ws').Server;
  3. var wss = new WebSocketServer({server: server}); // server is express' server instance.
  4. var clients = [];
  5.  
  6. wss.on('connection', function(ws) {
  7. console.log('connected');
  8. clients.push(ws);
  9. ws.on('close', function(){
  10. console.log('client closing');
  11. });
  12. ws.on('message', function(msg){
  13. console.log('message received');
  14. for (var i = 0, len = clients.length; i < len; i++)
  15. try {
  16. // do not use try-catch here, do it properly
  17. if (clients[i])
  18. clients[i].send(msg);
  19. }
  20. catch(e){
  21. clients[i] = null;
  22. }
  23. });
  24. });
  25.  

The code above is broadcasting a message to all connected clients.

It's very nice but it doesn't work on Android!

Workarounds:

  • Install Firefox or Chrome for Android, they support Websockets
  • Use a library that supports fall back to XHR long polling like Socket.io
  • Use Apache Cordova (phonegap) to create an Android app
  • Use a Flash implementation of websockets

If you use Apache Cordova you need to "provide" the websockets funcionality into webview using Java code. There are several plugins for that:

I haven't used any of those. The disadvantage is that users have to install an application. I just want them to use my web app without installing anything so I've discarded this option.

The flash implementation has some security constraints imposed by flash. I haven't dug into the subject much but I believe I need to open port 843 on the server and I can't do that on some PAAS providers. I can't confirm this, I might be wrong. The other thing is that browser needs the flash plugin. Take a look at this implementation (web-socket-js).

Eventually I've come back to Socket.io. Although people say it's outdated and it's got a poor websockets RFC implementation, it works very well for basic stuff and falls back to XHR long polling automatically:

  1.  
  2. var io = require('socket.io').listen(server); // server is express' server instance
  3. io.configure(function () {
  4. io.set("transports", ["websocket", "xhr-polling"]); // support both
  5. io.set("polling duration", 10);
  6. });
  7.  
  8. io.sockets.on('connection', function(socket){
  9. socket.on("sendMessage", function(msg){
  10. io.sockets.emit("messageReceived", msg); // broadcasting
  11. });
  12. });
  13.  
  14.  

On modern browsers implementing websockets, it will use them. On Android it will just use long polling.

To finish off, just remember that your mobile device and your desktop pc are two separate machines. If your client side js is trying to connect to "localhost" as the websockets server, it's not going to work from your mobile. I know it's absolutely obvious but I wasted more time than I expected not realizing that I had the wrong url in the client side js. It was written "localhost" rather than "192.168.0.100" for my tests using the Local Area Network. It was one of those silly mistakes that steal one's time more than they should 🙁

Enjoyed reading this post?
Subscribe to the RSS feed and have all new posts delivered straight to you.
  • Steve Purves

    Hi Carlos,

    Where did the localhost come from? from ‘doing the simplest thing possible’ at an earlier stage? which is the right thing to do! but that exact thing has caught me out before when I did my last (and only so far) browser based app with node & backbone. at the time its something that I though I’d need an integration test running in a “deployed” environment in order to catch, a level or two up the “testing onion” from the unit tests & feature tests.

    I hadn’t realised that sockets.io was thought of as outdated though (guess i’ve been in C++ world for too long, that’s were really old stuff lives 🙂 ). I like sockets.io, it’ll use websockets if active but its the fallback position through different transports that makes it reliable. reliable is good 🙂

    Thanks for the post!
    Steve

  • carlosble

    Hi Steve!
    Yes the “localhost” came up from being developing on my local server. Since I am not sysadmin for many years now, “localhost” doesn’t mean “this machine” on my head, it just means “the local development environment”, and using my phone on my LAN sounds like “local development environment” so that is why I ended up loosing time unaware of the silly problem 🙂
    There are several online tools to run js tests from mobile devices. I’ve got integration tests for this, in fact I’ve got all kind of tests for this app (will open source it into Bitbucket soon).

    Regarding C++, it’s a very important language. The other day I realized that the majority of the software I use, and that it’s reliable works on C++ and C: the browser, the OS, development tools… and if you have a look at Firefox’s code, you’ll see it’s pretty well-written. I have a profound respect for professional C++ developers 🙂

    Thanks for your comment man!

  • http://dmitry.eu/ Dmitry Polushkin

    socket.io is outdated, currently most used is an engine.io.

  • http://www.carlosble.com/ Carlos Ble

    Thanks Dmitry 🙂 apparently as both tools belong to the same author, socket.io will contain engine.io in version 1.0