注目の記事

iOSアプリからnode.js+Socket.IOと双方向通信する

2013.01.24

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

iOSアプリからUIWebViewなどを介さずにnode.js+Socket.IOと双方向通信するための簡単なサンプルを紹介します。

サーバ側の実装

iOSアプリからnode.js+Socket.IO間で双方向通信するには、socket.IO-objcというライブラリを使用します。 今回はサーバ側には弊社うえじゅん氏が公開している記事で作ったチャットアプリを使用しますので、まずは以下の記事を参考にチャットアプリを作っちゃってください。

Node + Socket.IO で簡単なチャットアプリの作成

チャットアプリの準備が終わったら、早速iOSアプリ側の準備をしましょう。ここからは以下の環境を前提に説明します。

Mac OS X 10.8 Moutain lion
Xcode 4.5.2
iOS SDK 6.0

iOSアプリの実装

サンプルプロジェクトのダウンロード

今回紹介するiOSアプリのソースコードをGitHubにあげてあるのでダウンロードしてください。
hirai-yuki/SocketIOSample

サーバ側を起動した状態で、iOSのサンプルアプリを起動してみてください。ブラウザを立ち上げて「http://localhost:3000」にアクセスしメッセージを送信すると、iOS側の表示が更新されます。逆にiOSアプリからメッセージを送信すると、ブラウザ側の表示が更新されます。

実行例

必要なフレームワーク・ライブラリの設定

ここからは要点をしぼって解説します。

必要なライブラリのダウンロード

iOSアプリからnode.js+Socket.IO間で双方向通信するにはsocket.IO-objcと、このライブラリを使用するために必要なSocketRocketjson-frameworkを使用します。

socket.IO-objc
pkyeck/socket.IO-objc
SocketRocket
square/SocketRocket
json-framework
stig/json-framework

ダウンロードしたライブラリのインポート

ダウンロードしたライブラリをインポートします。各ライブラリで必要なファイルは以下の通りです。

socket.IO-objc
  • SocketIO.h
  • SocketIO.m
  • SocketIOJSONSerialization.h
  • SocketIOJSONSerialization.m
  • SocketIOPacket.h
  • SocketIOPacket.m
  • SocketIOTransport.h
  • SocketIOTransportWebsocket.h
  • SocketIOTransportWebsocket.m
  • SocketIOTransportXHR.h
  • SocketIOTransportXHR.m
SocketRocket
SocketRocket/SocketRocketディレクトリ以下のファイルすべて
json-framework
json-framework/Classesディレクトリ以下のファイルすべて

設置場所はどこでも構いませんが、参考までに自分の設置例をのせておきます。

設置例

ビルトインのフレームワーク・ライブラリの設定

SocketRocketでは以下のフレームワーク・ライブラリに依存するので、リンクしましょう。

  • libicucore.dylib
  • CFNetwork.framework
  • Security.framework
  • Foundation.framework(プロジェクト作成時に既にリンクされているはず)

ビルトインのフレームワーク・ライブラリの設定

socket.IO-objcの使い方

SocketIODelegateプロトコル

TableViewController.hでは、socket.IO-objcのデリゲートメソッドを実装するために、SocketIODelegateプロトコルの実装を宣言します。

TableViewController.h

//
//  TableViewController.h
//  SocketIOSample
//
//  Created by hirai.yuki on 2013/01/24.
//  Copyright (c) 2013年 hirai.yuki. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "SocketIO.h"

@interface TableViewController : UITableViewController <SocketIODelegate>

@end

SocketIODelegateプロトコルでは、以下のメソッドが定義されていますので、適宜実装しておきましょう。

- (void)socketIODidConnect:(SocketIO *)socket;
サーバとの接続が確立されたときに実行されるメソッド。
- (void)socketIODidDisconnect:(SocketIO *)socket disconnectedWithError:(NSError *)error;
サーバとの接続が切断されたときに実行されるメソッド。
- (void)socketIO:(SocketIO *)socket didReceiveMessage:(SocketIOPacket *)packet;
メッセージを受信したときに実行されるメソッド。
- (void)socketIO:(SocketIO *)socket didReceiveJSON:(SocketIOPacket *)packet;
JSONを受信したときに実行されるメソッド。
- (void)socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet;
イベントを受信したときに実行されるメソッド。
- (void)socketIO:(SocketIO *)socket didSendMessage:(SocketIOPacket *)packet;
メッセージを送信したときに実行されるメソッド。
- (void)socketIO:(SocketIO *)socket onError:(NSError *)error;
エラー発生時に実行されるメソッド。

SocketIOインスタンス生成

実際にサーバ側と通信するためのクラスであるSocketIOインスタンスを生成します。インスタンスの生成には、- (id)initWithDelegate:(id)delegateメソッドを使用します。

TableViewController.m

...

- (void)viewDidLoad
{
    [super viewDidLoad];
    
...

    // socketIOクライアント生成
    self.socketIO = [[SocketIO alloc] initWithDelegate:self];
}

...

サーバと接続

サーバとの接続には、SocketIOクラスの以下のメソッドを使用します。

  • - (void) connectToHost:(NSString *)host onPort:(NSInteger)port
  • - (void) connectToHost:(NSString *)host onPort:(NSInteger)port withParams:(NSDictionary *)params
  • - (void) connectToHost:(NSString *)host onPort:(NSInteger)port withParams:(NSDictionary *)params withNamespace:(NSString *)endpoint
...

- (void)applicationDidBecomeActive
{
    // localhost:3000に接続開始
    [self.socketIO connectToHost:@"localhost" onPort:3000];
}

...

イベントの送信

イベントの送信には、- (void)sendEvent:(NSString *)eventName withData:(NSDictionary *)dataメソッドを使用します。

...

- (IBAction)sendEvent:(id)sender
{
    // 文字が入力されていなければ何もしない
    if (self.formCell.textField.text.length == 0) {
        return;
    }
    
    // イベント送信
    [self.socketIO sendEvent:@"message:send" withData:@{@"message" : self.formCell.textField.text}];

    // テキストフィールドをリセット
    self.formCell.textField.text = @"";
}

...

イベントの受信

イベントの受信は、デリゲートメソッドである- (void)socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packetメソッドで定義します。

...

- (void)socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet
{
    NSLog(@"%s", __func__);
    
    if ([packet.name isEqualToString:@"message:receive"]) {
        // メッセージが空でなければ追加
        if (packet.args[0][@"message"]) {
            [self.datas insertObject:packet.args[0][@"message"] atIndex:0];
            [self.tableView reloadData];
        }
    }
}

...

まとめ

ご覧の通り、socket.IO-objcを使用すればiOSアプリからnode.js+Socket.IO間で双方向通信が簡単に実現できます。まだ業務でゴリゴリ使っていないので何とも言えませんが、はまりどころがあれば報告します!