Tara Calihman - February 06, 2014
Technically, WebSockets allow a long-held single TCP socket connection to be established between the client and the server, removing the need to poll the server and allowing messages to be sent back and forth while keeping the connection open. But the real importance is that WebSockets provide a way to build scalable, real-time web applications.
We’re using WebSockets at VictorOps because the ability to chat in real-time is an integral part of solving a problem faster. Our app includes an incident timeline that features a Twitter-like feed for alerting platforms with chat making up an important piece of our functionality.
Now that we’ve established just how awesome WebSockets are, we must mention that we’ve run into a few challenges with our Android implementation using them. The big one is that there is currently only one well-documented, tested and regularly updated library: Autobahn.ws. If you do not need your transport layer encrypted it should work well, even though it not yet at a 1.0 release. However, we need that layer of security for our clients and at the time of this writing, Autobahn is using Java NIO (which gives a significant boost in performance over traditional sockets). The problem is a nasty little bug in Android’s implementation of Java NIO and TLS (see Android Issue #12955). Autobahn has a pull request that adds TLS using SSLSockets, but it fails some of the automated tests and has not been touched for months.
Besides Autobahn.ws, there are a few other libraries on github that we have experimented with. Most of them are forks of the Autobahn code, rewriting the parts of the NIO SocketChannel code to use SSLSockets. Among the projects tried are; koush’s android-websockets which is nowhere near production-ready as portrayed by the author: “This project is not yet done and I don’t recommend using it just yet.”, fatshotty’s socket.io-java-client which still has SSL issues and the current solution only works on Android 4.2+. Lastly, we found palmerc’s SecureWebSockets, which seems to be one of the more stable forks of Autobahn, although we still needed to do a few modifications.
There are other challenges in dealing with WebSockets and native Android apps. For one, Android is REST- friendly which means that it can live in a simple stateless architecture that generally runs over HTTP. Google has many REST-based tutorials and talks, as well as example apps. Additionally, you run into issues with your WebSocket when dealing with getting data out of a guaranteed order. The way we solved this was by adding in transaction ids and timeouts to replicate a request-response cycle. Also, when a view depends on multiple messages, we currently fill in as we receive data. But the plan is to modify the view with a loading UI until a minimum set of data is received, then display the fully built UI to the user.
And finally, there are the mobile constraints to take into consideration. Factors such as mobile data and power usage contribute to problems because holding a connection open can cause battery drain issues. We have solved some of these constraints in VictorOps by only holding the connection open while the user has the app in the foreground. Otherwise, we rely on push notifications and SMS to keep the user informed of major changes in state (alerts, chats, mentions).
We’re solving for these challenges at VictorOps by currently using a modified version of palmerc’s SecureWebSockets (itself is a modified version of Autobahn). Unfortunately palmerc’s code puts the connect logic on the calling thread (in our case it was the UI thread). This would cause the UI to halt until a connection was created or failed. Our solution is that we are now handling the connection logic on a new thread. In order to deal with the long disconnection times, we only create a WebSocket connection when the app is in the foreground. This is obviously still a work in progress but we welcome the opportunity to learn and share our hard-won knowledge with others.