Real Time applications with
WebSockets / WorkShop
Sergi Almar i graupera
@sergialmar

Romanian mobile systems community conference (mobos)
November 2013 - cluj Napoca
Agenda
•

Part 1 - Architecture and Dependency Injection with Android

•

Part 2 - Building the Server in Node.js and Socket.io

•

Part 3 - Building the Android client
Collaborative Apps
Multiplayer Games
Multimedia Chat
Social Feeds
Sports Updates
Financial Tickets
Clickstream Data
Online Education
Location-based Apps
Real-time data on the web
•

Polling

•

Long polling / Comet

•

Flash
Problem

Applications need two-way communication
Too many connections and overhead with ajax / comet
WebSockets
two-way real time communication
WebSockets
•

Real-time full duplex communication over TCP

•

Uses port 80 / 443 (URL scheme: ws:// and wss://)

•

Small overhead for text messages (frames)
•

•

0x00 for frame start, 0xFF for frame end (vs HTTP 1K)

Ping / pong frames for staying alive
WebSocket Handshake
GET /mychat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13
Origin: http://example.com

client sends a WebSocket handshake request
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

server response
WebSocket API
var ws = new WebSocket('ws://www.romobos.com/ws');

!

// When the connection is open, send some data to the server
ws.onopen = function () {
ws.send('Ping'); // Send the message 'Ping' to the server
};

!

// Log errors
ws.onerror = function (error) {
ws.log('WebSocket Error ' + error);
};

!

// Log messages from the server
ws.onmessage = function (e) {
ws.log('Server: ' + e.data);
};
What we are gonna build
(real-time chat app)
websoc

kets

w

ckets
ebso
Dependency Injection
decouple components, flexible code, reduce
boilerplate, testable code
Dependency Injection in Android
•

RoboGuice

•

Dagger

•

Transfuse

•

Android annotations
RoboGuice
•

Dependency Injection framework

•

Uses Google Guice as the backbone

•

Supports JSR-330
Extending from RoboGuice
•

RoboActivity

•

RoboListActivity

•

RoboMapActivity

•

RoboPreferenceActivity

•

RoboFragmentActivity

•

RoboFragment

•

RoboService

•

…
Injecting Views
<TextView
android:id="@+id/text1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
/>

@InjectView(R.id.text1) TextView mSampleText;
Injecting Resources
@InjectResource(R.anim.my_animation) Animation myAnimation;

!
@InjectResource(R.drawable.icon)
!

Drawable icon;

@InjectResource(R.string.app_name) String myName;
Injection POJOs
@Singleton
public class MyPojo {
private String myField;

!

public void myMethod() {
...
}

}

@Inject private MyPojo myPojo;
Custom Binding
public class MyModule implements Module {
@Override
public void configure(Binder binder) {
binder.bind(IFoo.class).to(SimpleFoo.class);
}
}

define a module
public class App extends Application {

!
!

@Override
public void onCreate() {
super.onCreate();

RoboGuice.setBaseApplicationInjector(this,
RoboGuice.DEFAULT_STAGE,
RoboGuice.newDefaultRoboModule(this),
new MyModule());
}
}

let RoboGuice know about it
Traditional Approach
class AndroidWay extends Activity {
TextView name;
ImageView thumbnail;
LocationManager loc;
Drawable icon;
String myName;

!

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
name
= (TextView) findViewById(R.id.name);
thumbnail = (ImageView) findViewById(R.id.thumbnail);
loc
= (LocationManager) getSystemService(Activity.LOCATION_SERVICE);
icon
= getResources().getDrawable(R.drawable.icon);
myName
= getString(R.string.app_name);
name.setText( "Hello, " + myName );
}
}
RoboGuice Approach
@ContentView(R.layout.main)
class RoboWay extends RoboActivity {
@InjectView(R.id.name)
@InjectView(R.id.thumbnail)
@InjectResource(R.drawable.icon)
@InjectResource(R.string.app_name)
@Inject

!

TextView name;
ImageView thumbnail;
Drawable icon;
String myName;
LocationManager loc;

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
name.setText( "Hello, " + myName );
}
}
Lab I
https://github.com/salmar/android-websocketsmobos2013/wiki
Part II
Building the Server with NodeJS
and Socket.io
Node.js
event driven, non-blocking server
side JS
Google V8 Engine
•

Open source JS engine by Google (used in Google
Chrome)

•

No JIT, all JS compiled to assembler

•

Optimisations like inlining, elision of runtime
properties…

•

Improved garbage collector
CommonJS
•

Set of specifications for JS outside the browser

•

Node.js implements some specifications
•

i.e modules
•

There should be a function called require

•

There should be a var called exports
Modules
•

Node.js provides some core modules like http, tcp, fs, sys…
•

will look for the module in the node_modules dir
hierarchically

•

if not found, will look in the paths outlined in
NODE_PATH

var http = require('http');
Module Example
var PI = Math.PI;
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};

module definition in myModule.js

var myModule = require('./myModule.js');

include myModule.js in some other file
Dependency Management
Node packet manager (npm)
express (routing), socket.io (websockets)…
Sergis-MacBook-Air:tmp salmar$ npm install express
npm http GET https://registry.npmjs.org/express
npm http 200 https://registry.npmjs.org/express
npm http GET https://registry.npmjs.org/express/-/express-3.4.4.tgz
npm http 200 https://registry.npmjs.org/express/-/express-3.4.4.tgz
npm http GET https://registry.npmjs.org/connect/2.11.0
npm http GET https://registry.npmjs.org/commander/1.3.2
npm http GET https://registry.npmjs.org/methods/0.1.0
npm http GET https://registry.npmjs.org/range-parser/0.0.4
npm http GET https://registry.npmjs.org/mkdirp/0.3.5
npm http GET https://registry.npmjs.org/cookie/0.1.0
npm http GET https://registry.npmjs.org/buffer-crc32/0.2.1
npm http GET https://registry.npmjs.org/fresh/0.2.0
npm http GET https://registry.npmjs.org/cookie-signature/1.0.1
npm http GET https://registry.npmjs.org/send/0.1.4
npm http GET https://registry.npmjs.org/debug
npm http 200 https://registry.npmjs.org/methods/0.1.0
npm http 304 https://registry.npmjs.org/range-parser/0.0.4
npm http GET https://registry.npmjs.org/methods/-/methods-0.1.0.tgz
npm http 200 https://registry.npmjs.org/commander/1.3.2
npm http GET https://registry.npmjs.org/commander/-/commander-1.3.2.tgz
npm http 304 https://registry.npmjs.org/cookie/0.1.0
…

!

express@3.4.4 node_modules/express
├── methods@0.1.0
├── range-parser@0.0.4
├── cookie-signature@1.0.1
├── fresh@0.2.0
├── debug@0.7.4
├── buffer-crc32@0.2.1
├── cookie@0.1.0
├── mkdirp@0.3.5
├── commander@1.3.2 (keypress@0.1.0)
├── send@0.1.4 (mime@1.2.11)
└── connect@2.11.0 (methods@0.0.1, uid2@0.0.3, pause@0.0.1, qs@0.6.5, raw-body@0.0.3, bytes@0.2.1, negotiator@0.3.0,
package.json
{
"name": "Mobos Chat",
"version": "1.0.0",
"description": "Real time chat",
"author": "salmar",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"socket.io": "latest",
"express": "latest",
"jade": "latest"
}
}

npm install
Web Server in NodeJS
var http = require('http');

!

http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello Worldn');
}).listen(1337, '127.0.0.1');

!

console.log('Server running at http://127.0.0.1:1337/');
Running the app
Sergis-MacBook-Air:tmp salmar$ node app.js
Server running at http://127.0.0.1:1337/
Express.js
sinatra inspired web framework for node.js
Express.js
var express = require('express');
var app = express();

!

app.get('/', function(req, res){
res.send('Hello World');
});

!

app.listen(3000);
Socket.io

abstraction layer for WebSockets
http://caniuse.com/#feat=websockets / Nov 2013
Socket.io
•

Abstraction layer for WebSockets

•

Fallback to:
•

Flash socket

•

AJAX Long-polling

•

AJAX multi-part streaming

•

JSONP polling

•

iFrame
Handling Events
io.sockets.on('connection', function(socket) {});

initial connection from client
socket.on('message', function(message) {})

message handler triggered when message is received
socket.on('disconnect', function() {})

triggered when socket disconnects
socket.on('custom_event', function(data) {})

event handler for custom event
Sending messages
socket.send(JSON.stringify({user:'sergi',
message: 'Welcome to Mobos'})
);

sends a message to the connected client
socket.broadcast.send(JSON.stringify({user:’sergi',
message: 'Welcome to Mobos'})
);

sends a message to all clients except the owner of the socket
Emitting Events
socket.emit('user:join', {name: 'sergi'});

triggers a custom event

socket.broadcast.emit('user:joined', data);

sends a message to all clients except the owner of the socket
Attach information to the socket

socket.set('nickname', data.name, <optional_callback>);
Lab II
https://github.com/salmar/android-websocketsmobos2013/wiki
Part III
Building the Android client with
Socket.io
Otto
enhanced event bus with emphasis on Android support
publish

subscribe

Activity
Activity

Activity
FRAGMENT
SERVICE
POJO

bus

Activity
FRAGMENT
Otto
•

Forked from Guava’s EventBus

•

Lightweight - 19k

•

Fast, optimised for Android
Publishing
Bus bus = new Bus();

creates the bus (better use dependency injection)

bus.post(new ServerMessage("This is awesome"));

publish the message
synchronous delivery
Subscribing
@Subscribe
public void receiveMessage(ServerMessage serverMessage) {
// TODO: React to the event somehow!
}
Otto API
•

register(), unregister(), post()

•

@Subscribe, @Produce

•

Thread confinement

•

Easy to test
SocketIO for Android
•

There’s no official library, but there are community
libraries, sometimes buggy :(
•

•

https://github.com/fatshotty/socket.io-java-client

Server-like API
Callbacks
!
!
!
!
!

public void onMessage(JsonElement json, IOAcknowledge ack) {
}
public void onMessage(String data, IOAcknowledge ack) {
}
public void onError(SocketIOException socketIOException) {
}
public void onDisconnect() {
}
public void onConnect() {
}
public void on(String event, IOAcknowledge ack, JsonElement... args) {
}
Lab III
https://github.com/salmar/android-websocketsmobos2013/wiki
Thank you!
@sergialmar

Building Real-Time Applications with Android and WebSockets