Socket.IO-Client-Swiftでリアルタイム通信

こんにちは増島です。
アプリ内でリアルタイム通信機能を入れようと思い、 折角なので使ったことのないSocket.ioを使ってみました!!

今回はイベントの送信や受信の実装部分を簡単に説明したいと思います!

Socket.IO-Client-Swift

ネイティブ側のライブラリは「Socket.IO-Client-Swift」を使用しました。 Socket.IO-Client-SwiftはSocket.ioの公式Swiftクライアントライブラリです。
iOS用のクライアントライブラリは他にも「SocketRocket」「SIOSocket」などがあるようです。
https://github.com/facebook/SocketRocket
https://github.com/MegaBits/SIOSocket

サーバ側の実装

サーバ側のsocketの部分はこんな感じで実装しています。

// ########## Socket ##########
var http = require('http').Server(app);  
var io = require('socket.io')(http);

io.on('connection', function(socket){  
    console.log("connect")

    socket.on('disconnect', function(){
      console.log("disconnect");
    });

    socket.on('join', function(info){
      console.log("join:" + info.room_id);
      socket.join(info.room_id);
    });
});

// http.listen(3001, function(){
http.listen(portSocket, function(){  
  console.log('socket listening on *:' + portSocket);
});

ライブラリの導入

「Socket.IO-Client-Swift」はCocoaPodsに対応してるのでPodファイルに書くだけで簡単にインストールできます。
Carthageにも対応してるのでCarthageを使っている方も安心してください!

Podfile

use_frameworks!  
target 'xxx' do  
  pod 'Socket.IO-Client-Swift'
end  

Cartfile

github "socketio/socket.io-client-swift"

オブジェクトの生成

SocketIOClientクラスのオブジェクトを生成する際に、再コネクト待ち時間など色々なオプションを設定することができます。

let options: Set<SocketIOClientOption> = Set(arrayLiteral:.Log(true),.Reconnects(true),.ReconnectWait(5))  
self.socket = SocketIOClient(socketURL:"http://xxxxx", options: options)  

接続と切断

接続、切断は下のコードだけで出来ます。簡単です!

self.socket.connect()  
self.socket.disconnect()  

受信イベントの設定

受信イベントを処理するにはハンドラー登録します。 第一引数にイベント名を指定し、第二引数に受信時の処理をクロージャで渡します。

self.socket.on("event1", callback: {  
    (data:[AnyObject], emitter:SocketAckEmitter) -> Void in
    print("Receive Event1")
})

一度だけ受信したいイベントの処理を登録することも出来ます!

self.socket.once("onceEvnet", callback: {  
    (data:[AnyObject], emitter:SocketAckEmitter) -> Void in
    print("Receive Once Event")
})

全てのイベントの受信に対する処理を登録する場合はこのようになります

self.socket.onAny{  
    (handler:SocketAnyEvent) -> Void in
    let event = handler.event
    let items = handler.items
    print("Receive \(event)")
    print(items)
}

errorハンドリング

エラーイベントは通常イベントのように登録します。

self.socket.on("error", callback: {  
    (data:[AnyObject], emitter:SocketAckEmitter) -> Void in
    print("Receive Error")
})

自分でエラーを通知する場合だけでなく、 サーバ接続に失敗した場合などにもこのイベントが自動で通知されます。

送信

サーバにメッセージを送信するにはemitを使用します。

let params = ["sender" : "taro", "message" : "おはよう!"]  
self.socket.emit("event1", params)  

emitを実行すると自分を含めた接続中のクライアントにメッセージが届きます。

roomにjoin

Socket.ioはメッセージの送信相手をフィルタリングする為にroomとnamespaceの二つの仕組みが用意されています。
それぞれの違いなどについては下記の記事が参考になります。
http://blog.afnf.net/blog/37

namespaceについてはアプリ側からjoinすることが出来るのですが、
roomについてはクライアントライブラリからjoinする機能が提供されておらず、
サーバ側でハンドリングする必要があります。

アプリ側からは通常のイベントでemitし、サーバ側でroomのjoinみ該当するイベントを受信したらそのsocketをルームにjoinさせる仕組みで実装します。

アプリ側

self.client.emit("join", items: ["room_id":"room01"])  
サーバ側

socket.on('join', function(info){  
    console.log("join:" + info.room_id);
    socket.join(info.room_id);
});

サーバ側もアプリ側も非常に簡単に実装できました!! 簡単なチャットアプリなどだったらサクッと作れそうで非常に便利ですね!!