AS3WebSocketを利用してHeroku WebSocketとAIR for Androidを連携したメモ

最近、色々な仕組みと連携するために、JavaScriptを中心にしてWebSocketやSocketIOであれこれ試しています。

当然、FLASHでも連携したいと思い、AS3WebSocketを利用してHeroku WebSocketとAIR for Androidを連携したメモです。

参考記事

Socketと連携するFLASHの記事はもうだいぶ昔の記事が多いものの、今までサーバー側の仕組みを作るのに苦労していたところがHerokuで作れるようになってきました(個人的に)

この「フロントエンド側・バックエンド側両面で作りやすそう」という視点を軸に、改めて探しまして以下記事に出会いました。

AS3 と Python を WebSocket で接続するついでに mongodb でほげほげするメモ | デブ ハゲ

まさにこれでして!

サーバー側

今回はシンプルに

* meinheld
* flask
* mongoengine

という構成。

をHeroku NodeJS WebSocketに置き換えればいいなと。

まずHeroku WebSocketサーバーを立てる

ではHerokuでWebSocketサーバーを立てます。

ちゃんと本家にサンプルがある

Herokuにサンプルあります。

Using WebSockets on Heroku with Node.js | Heroku Dev Center

デプロイまで進む

途中、丁寧にソースコードが説明されていますが飛ばして、まずデプロイまでやってしまいます。

Option 1. Clone sample app を進める

git clone https://github.com/heroku-examples/node-ws-test.git

mkdir node-ws-test

cd node-ws-test

DeployのCreate the Heroku app to deploy to: 以降をすすめる。

heroku create

git push heroku master

今回は hoge-hoge-ws-as3-test.herokuapp.com という例で進めます。

サーバーにアクセス

サーバーに

http://hoge-hoge-ws-as3-test.herokuapp.com/

アクセスすると、

as3websocket-heroku-websocket-air-for-android_2

と表示されます。WEB画面がメッセージを受け取っているだけです。

WebSocket自体は、タイムスタンプ 2015-05-28T05:41:24.494Z という文言を吐き続けています。

AIR側の実装

続いて、AIR側の実装です。ほぼ参考記事のとおりですが、もう少しアプリ上で状態が見えるように、テキストを吐き出すようにします。

ライブラリ持ってくる

theturtle32/AS3WebSocket

からライブラリを持ってきて、以下のように書いてみましょう。

実際のコード

package {

import flash.display.Sprite;
import flash.text.TextField;

import com.worlize.websocket.WebSocket;
import com.worlize.websocket.WebSocketError;
import com.worlize.websocket.WebSocketErrorEvent;
import com.worlize.websocket.WebSocketEvent;
import com.worlize.websocket.WebSocketMessage;

import flash.display.Sprite;
import flash.events.IOErrorEvent;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;

[SWF(width="480",height="820",frameRate="60",backgroundColor="#000000")]

public class WebSocketMain extends Sprite {

    public var txtMessage:TextField;
    public var txtStatus:TextField;

    private var _ws:WebSocket;

    public function WebSocketMain() {

        // 結果の文言の出力部部分 //////////////////////////////////////
        var ftStatus:TextFormat = new TextFormat();
        ftStatus.font = "Arial";
        ftStatus.size = 24;
        ftStatus.color = 0xffffff;

        txtStatus = new TextField();
        txtStatus.multiline = true;
        txtStatus.wordWrap = true;
        txtStatus.defaultTextFormat = ftStatus;
        txtStatus.x = 30;
        txtStatus.y = 60;
        txtStatus.width = 450;
        txtStatus.text = "--";
        txtStatus.autoSize = TextFieldAutoSize.LEFT;
        addChild(txtStatus);

        var ftMessage:TextFormat = new TextFormat();
        ftMessage.font = "Arial";
        ftMessage.size = 36;
        ftMessage.color = 0xffffff;

        txtMessage = new TextField();
        txtMessage.defaultTextFormat = ftMessage;
        txtMessage.text = "--";
        txtMessage.autoSize = TextFieldAutoSize.LEFT;
        addChild(txtMessage);

        // WebSocketの実際のコードは以下から ////////////////////////////
        _ws = new WebSocket("ws://hoge-hoge-ws-as3-test.herokuapp.com/","*");
        _ws.addEventListener( WebSocketEvent.OPEN, _connectedHandler);
        _ws.addEventListener( WebSocketEvent.CLOSED, _closeHandler );
        _ws.addEventListener( WebSocketEvent.MESSAGE, _messageHandler );
        _ws.addEventListener( WebSocketErrorEvent.CONNECTION_FAIL, _errorHandler );
        _ws.addEventListener( IOErrorEvent.IO_ERROR, _ioErrorHandler );
        _ws.connect();

    }

    /**
     * 接続完了
     * @param event WebSocketEvent
     */
    private function _connectedHandler(event:WebSocketEvent):void
    {
        trace("connected!", event );
        txtStatus.text = "connected! " + event.toString();

        var text:String = String(new Date().time) + "hoge"
        _ws.sendUTF(text);
    }

    /**
     * 接続終了
     * @param event WebSocketEvent
     */
    private function _closeHandler(event:WebSocketEvent):void
    {
        trace("closed...", event);
        txtStatus.text = "closed... " + event.toString();
    }

    /**
     * メッセージ受信
     *
     * @param event WebSocketEvent
     */
    private function _messageHandler( event:WebSocketEvent ):void
    {
        trace("msg!");
        trace("event.message.utf8Data");
        // 文言の出力 ここがHeroku WebSocketの文言と同様になる
        // つまりタイムスタンプ
        txtMessage.text = event.message.utf8Data;
        txtStatus.text = "msg! [event.message.utf8Data] " + event.toString();
    }

    /**
     * WebSocketError
     *
     * @param event WebSocketErrorEvent
     */
    private function _errorHandler( event:WebSocketErrorEvent ):void
    {
        trace("ws error...", event.text );
        txtStatus.text = "ws error..." + event.text;
    }

    /**
     * IOError
     *
     * @param event IOErrorEvent
     */
    private function _ioErrorHandler( event:IOErrorEvent ):void
    {
        trace("io error...", event.text );
        txtStatus.text = "io error..." + event.text;
    }


}
}

書き換える部分

http://hoge-hoge-ws-as3-test.herokuapp.com/

にサーバが立った場合ですが、接続先を変えればすぐ使えます。

ws://hoge-hoge-ws-as3-test.herokuapp.com/

以下のようにコードを書き換えています。

_ws = new WebSocket("ws://hoge-hoge-ws-as3-test.herokuapp.com/","*");

動作確認

こちらを敢えてだいぶ前のSDK flex4.13.0 air15.0.0.302 でAPKを出力しAndroidで読み込んだところ、無事動きました。

アプリとして動いているもののキャプチャです。

as3websocket-heroku-websocket-air-for-android_3

上部テキストが実際のメッセージの受信部分。下部テキストはいろいろな状態を出力してます。

Androidのパーミッション

パーミッションは特に難しいことはなくINTERNETを解放しておきましょう。

<uses-permission android:name="android.permission.INTERNET"/>

おわりに

テンション上がる!

Socket系は最近はかなり実装しやすくなっている印象です。

これでリアルタイムに色々と繋げられつつ、サポートしている範囲も広くなってきているので、ネタ同士の優れた接着剤になっていきそうですね!

それでは、よき Adobe AIR + Heroku + NodeJS + WebSocket Lifeを!(長いw)