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

Android
252件のシェア(すこし話題の記事)

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

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

サーバ側の実装

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

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

チャットアプリの準備が終わったら、早速Androidアプリ側の準備をしましょう。

Androidアプリの実装

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

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

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

android-node-socketio

必要なライブラリの設定

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

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

Androidアプリからnode.js+Socket.IO間で双方向通信するにはsocket.io-java-clientを使用します。以下のリンクからダウンロードして下さい。

socket.io-java-client
Gottox / socket.io-java-client

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

ダウンロードしたライブラリをインポートします。ダウンロードしたライブラリはソースの状態なのでantを使ってjarファイルにアーカイブします。 build.xmlのあるディレクトリに移動してから以下のコマンドを実行すると、jarディレクトリ内にsocketio.jarというjarファイルが作成されます。これをAndroidプロジェクトのlibディレクトリ内に入れればインポートは完了です。

ant jar

socket.io-java-clientの使い方

IOCallbackインターフェイス

IOCallbackインターフェイスでは、以下のメソッドが定義されていますので、適宜実装しておきましょう。

public void onConnect()
サーバとの接続が確立されたときに実行されるメソッド。
public void onDisconnect()
サーバとの接続が切断されたときに実行されるメソッド。
public void onMessage(JSONObject json, IOAcknowledge ack)
JSONを受信したときに実行されるメソッド。
public void onMessage(String data, IOAcknowledge ack)
メッセージを受信したときに実行されるメソッド。
public void on(String event, IOAcknowledge ack, Object... args)
イベントを受信したときに実行されるメソッド。
public void onError(SocketIOException socketIOException)
エラー発生時に実行されるメソッド。

私は以下のように実装しました。

private IOCallback iocallback = new IOCallback() {

		@Override
		public void onConnect() {
		    System.out.println("onConnect");
		}

		@Override
		public void onDisconnect() {
		    System.out.println("onDisconnect");
		}

		@Override
		public void onMessage(JSONObject json, IOAcknowledge ack) {
			System.out.println("onMessage");
		}

		@Override
		public void onMessage(String data, IOAcknowledge ack) {
		    System.out.println("onMessage");
		}

		@Override
		public void on(String event, IOAcknowledge ack, Object... args) {
			final JSONObject message = (JSONObject)args[0];

			new Thread(new Runnable() {
				public void run() {
				handler.post(new Runnable() {
					public void run() {
						try {
							if(message.getString("message") != null) {
								// メッセージが空でなければ追加
								adapter.insert(message.getString("message"), 0);
							}

							} catch (JSONException e) {
								e.printStackTrace();
							}
						}
					});
				}
			}).start();
		}

		@Override
		public void onError(SocketIOException socketIOException) {
		    System.out.println("onError");
		    socketIOException.printStackTrace();
		}
    };

サーバと接続

サーバとの接続するためにはまずSocketIOクラスのインスタンスを生成します。コンストラクタの引数に接続先のURLを設定して下さい。エミュレータを使ってローカルのサーバに接続する場合はlocalhostではなく10.0.2.2にします。
AndroidManifest.xml にandroid.permission.INTERNETのパーミッションを追加するのを忘れないようにして下さい。

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

  • void io.socket.SocketIO.connect(IOCallback callback)
  • void io.socket.SocketIO.connect(String url, IOCallback callback) throws MalformedURLException
  • void io.socket.SocketIO.connect(URLurl, IOCallback callback) throws MalformedURLException
private void connectSocketIO() throws MalformedURLException {
    // ローカルホストの3000のポートに接続開始
    socket = new SocketIO("http://10.0.2.2:3000/");
    socket.connect(iocallback);
}

イベントの送信

イベントの送信には、emitメソッドを使用します。emitメソッドの第1引数はイベント名、第2引数は送信するデータになります。

public void sendEvent(View view){
	// 文字が入力されていなければ何もしない
	if (editText.getText().toString().length() == 0) {
		return;
	}

	try {
		// イベント送信
		JSONObject json = new JSONObject();
		json.put("message", editText.getText().toString());
		socket.emit("message:send", json);

	} catch (JSONException e) {
		e.printStackTrace();
	}

	// テキストフィールドをリセット
	editText.setText("");
}

イベントの受信

イベントの受信は、IOCallbackインターフェイスのonメソッドで定義します。onメソッドの中でUIを操作しようとするとCalledFromWrongThreadExceptionがスローされるので注意して下さい。

@Override
public void on(String event, IOAcknowledge ack, Object... args) {
	final JSONObject message = (JSONObject)args[0];
	new Thread(new Runnable() {
		public void run() {
			handler.post(new Runnable() {
				public void run() {
					try {
						if(message.getString("message") != null) {
							// メッセージが空でなければ追加
							adapter.insert(message.getString("message"), 0);
						}
					} catch (JSONException e) {
						e.printStackTrace();
					}
				}
			});
		}
	}).start();
}

まとめ

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

  • http://twitter.com/mikehibm Makoto Ishida

    参考になる記事どうもありがとうございます!

    Android 2.2のエミュレータだと「java.net.SocketException: Bad address family」というエラーが起きましたが、下の様にすると上手く動きました。

    System.setProperty(“java.net.preferIPv6Addresses”, “false”);
    socket = new SocketIO(“http://10.0.2.2:3000/”);
    socket.connect(iocallback);

    • 袴田

      ありがとうございます。参考にさせて頂きます。

  • Kanayan Burauny

    webブラウザのソースを教えてほしいです。