【連載】

今からはじめるAIRプログラミング

14 通信用API - AIR⇔Flex/Flashも可能! LocalConnectionによるデータ送受信

    白石俊平  [2007/08/07]

    LocalConnectionとは?

    今回は、flash.net.LocalConnectionクラスについての解説を行う。

    LocalConnectionクラスとは、AIR以前からも存在した、Flex/Flashアプリケーション同士で通信を行うための仕組みである。同じマシン上で動作するSWFアプリケーション同士で行うことのできる、プロセス間通信だと思ってよい。APIが非常にシンプルな割には、ActionScriptのオブジェクトをそのまま渡す事ができるなど、かなり強力な仕組みだ。

    AIRではLocalConnectionはさらにパワーアップしており、AIRアプリケーション同士で通信をできるのみならず、ブラウザ上で動作しているFlexアプリケーションとも通信が可能だ。

    では、まずはLocalConnectionの使用法を見ていこう。

    LocalConnectionの使用法

    LocalConnectionは単純に言えば、文字列で名前を指定した接続を介して、クライアントとサーバが通信を行う仕組みだ。なので、送信側のコードと受信側のコードに分けて見ていくと分かりやすい。

    ということで、データを送信する側のコードを先に見ていこう。 送信側のコードは、簡単に書くと次のようになる。

    // (1) LocalConnectionのインスタンス作成
    var con:LocalConnection = new LocalConnection();
    
    // (2) 送信結果をハンドリングするためのリスナを追加
    con.addEventListener(StatusEvent.STATUS,
        function(event:StatusEvent):void {
            switch (event.level) {
                // 正常に送信完了
                case "status":
                    break;
                // エラー
                case "error":
                    break;
                // 警告
                case "warning":
                    break;
            }
        });
    
    // (3) データ送信
    con.send("接続名", "受信側のメソッド名", 引数...);
    

    (1) LocalConnectionのインスタンスを作成している。引数なしのコンストラクタを呼び出すだけだ。

    (2) 送信がエラー終了した時のために、イベントリスナを追加している。送信結果は、リスナメソッドの引数に渡されるflash.events.StatusEventクラスのlevelプロパティを参照すれば良い。

    (3) データの送信には、LocalConnectionクラスのsendメソッドを使用する。sendメソッドの第一引数に渡す「接続名」については後述。第二引数は、受信側でデータを受け取るために用意するメソッドの名前。第三引数以降がデータで、任意のオブジェクトを複数渡すことができる。

    では、send()メソッドの第一引数に渡す「接続名」について解説する。「接続名」とは、通信を行うアプリケーション同士で共有する文字列だ(例えば"myConnection"など)。さらに送信する側としては、受信側を特定するための情報を接続名の前に付与する必要がある。 これは以下のルールに則っている。

    • 受信側がFlexアプリケーションの場合は、そのSWFの配布元となったドメイン名を接続名の前に付与する。つまり、接続名は「www.example.com:myConnection」などとなる。間の「:」は、ドメイン名と接続名の間の区切り文字だ。

    • 受信側がAIRアプリケーションの場合は、「app#アプリケーションID」という文字列を接続名の前に付与する。アプリケーションIDとは、アプリケーションディスクリプタファイルのルート要素applicationの、appId属性で指定する任意の文字列だ(アプリケーションディスクリプタファイルについては、連載第3回にて解説を行っている)。例えば、アプリケーションIDが「jp.co.mycom.journal.App」だった場合、接続名は「app#jp.co.mycom.journal.App:myConnection」などとなる。

    では次に、受信側のコードを見ていこう。LocalConnection経由でデータを受信する側のコードは以下のようなものになる。

    // LocalConnectionのインスタンス作成
    var con:LocalConnection = new LocalConnection();
    
    // (1) 接続を許可するドメイン/アプリケーションIDを指定
    con.allowDomain("jp.co.mycom.journal.App");
    
    // (2) データの受信に失敗したイベントのリスナを登録
    con.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
    
    // (3) セキュリティ上許可していないドメイン/アプリから接続されたイベントのリスナを登録
    con.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
    
    // (4) データを受け取るメソッドを持つインスタンスを、
    //     `client`プロパティに指定
    con.client = this;
    
    // (5) 接続名を指定してconnectメソッドを呼び出す。
    con.connect("接続名");
    
    
    ...
    
    // (6) データ受信用のメソッド
    function onReceived(msg:String):void {
        ...
    }
    

    ポイントを解説していこう。

    (1) LocalConnectionのインスタンスを作成した後、(4)でconnect()メソッドを呼び出す前に、allowDomain()メソッドを使用して接続を許可するクライアントのドメイン、もしくはアプリケーションIDを指定する必要がある。受信側がFlexアプリケーションの場合は必須。AIRアプリケーションの接続では、これを行う必要はない。「*」(アスタリスク)を使用すると、接続名さえ正しければあらゆる接続を受け入れる。

    (2) クライアントが送ってきたデータを受信するのに失敗した(受信用のハンドラメソッドが存在しない、など)場合に発生するエラーを処理するためのリスナメソッドを登録している。

    (3) セキュリティ上許可していないドメイン/アプリケーションから接続された際に発生するエラーを処理するためのリスナメソッドを登録している。

    (4) 送信されたデータを受け取るメソッド(そのメソッド名は送信側のsend()メソッドで指定される)を持つインスタンスを、LocalConnectionclientプロパティに代入する。データが到着した際、そのメソッドがランタイムによって呼び出される。

    (5) 接続名を指定してconnect()メソッドを呼び出す。受信側は、送信側と違って接続名だけを使用する。

    (6) 送信側が送ったデータを引数に取るメソッドを用意しておく。メソッド引数の数と型は、送信側がsend()メソッドを呼び出す時に指定した引数と一致する必要がある。

    以上で、LocalConnectionを使用したコードの説明は終わりだ。では、今回のサンプルアプリケーションの解説に入ろう。

    サンプルアプリケーションの解説

    今回用意したサンプルは、データの送信側と受信側に分かれている。

    送信側のテキストエリアに文字を入力すると、ローカルコネクション経由で文字列が送られ、受信側のテキストエリアに反映される。

    テキストエリアに入力した文字列が自動で同期する

    また、受信側のコードを変えることなくFlexアプリケーションにしたとしても、送信側の接続文字列を変えるだけで同じように動作する。

    受信側をFlexにしても、ほとんど修正することなく動作する

    まず、送信側のソースコードは以下の通り。

    リスト: 送信側のAIRアプリケーション「AIRLocalConnectionExample.mxml」

    <?xml version="1.0" encoding="utf-8"?>
    <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
        <mx:Script>
            <![CDATA[
                import flash.net.LocalConnection;
    
                // LocalConnection.send()メソッドに渡す接続名
                //   受信側がローカルホスト上で動作するFlexアプリケーションの場合
                private static const CONNECTION_NAME:String = "localhost:myConnection";
                //   受信側がAIRアプリケーションの場合
                //private static const CONNECTION_NAME:String = "app#AIRLocalConnectionReceiver:myConnection";
    
                // ローカルコネクション
                private var con:LocalConnection = new LocalConnection();
    
                // creationCompleteで呼び出される初期化メソッド
                private function init():void {
                    // 送信結果をハンドリングするためのリスナを追加
                    con.addEventListener(StatusEvent.STATUS, onSend);
                }
                // テキストエリアの状態が変更されたら呼び出されるメソッド
                private function onTextChanged():void {
                    con.send(CONNECTION_NAME, "onTextReceived", textInput.text);
                }
                // send()メソッドの結果を処理するリスナメソッド
                private function onSend(event:StatusEvent):void {
                    if (event.level == "error") {
                        trace("Send Error");
                    }
                }
            ]]>
        </mx:Script>
        <mx:TextArea id="textInput" x="10" y="28" width="453" height="318" change="onTextChanged()"/>
        <mx:Label x="10" y="2" text="ローカルコネクションのサンプル"/>
    </mx:WindowedApplication>
    

    次に示すのが受信側のコードだ。

    リスト: 受信側のFlexアプリケーション「AIRLocalConnectionReceiver.mxml」

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
        <mx:Script>
            <![CDATA[
                import flash.net.LocalConnection;
    
                // ローカルコネクション
                private var con:LocalConnection = new LocalConnection();
    
                // creationCompleteで呼び出される初期化メソッド
                private function init():void {
                    // 接続を許可するドメイン/アプリケーションIDを指定
                    con.allowDomain("*");
                    // データの受信に失敗したイベントのリスナを登録
                    con.addEventListener(AsyncErrorEvent.ASYNC_ERROR, function(event:AsyncErrorEvent):void {
                        textOutput.text += (event.text + "\n");
                    });
                    // セキュリティ上許可していないドメイン/アプリから接続されたイベントのリスナを登録
                    con.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(event:SecurityErrorEvent):void {
                        textOutput.text += (event.text + "\n");
                    });
                    try {
                        // データを受け取るメソッドを持つインスタンスを、clientプロパティに指定
                        con.client = this;
                        // 接続名を指定してconnectメソッドを呼び出す
                        con.connect("myConnection");
                    } catch (e:ArgumentError) {
                        trace("接続名が既に使用されています。");
                    }
                }
                // データ受信用のメソッド
                public function onTextReceived(msg:String):void {
                    textOutput.text = msg;
                }
            ]]>
        </mx:Script>
        <mx:TextArea id="textOutput" x="10" y="28" width="453" height="318" editable="false"/>
        <mx:Label x="10" y="2" text="LocalConnection経由で受けとったテキストが下に表示されます。"/>   
    </mx:Application>
    

    今回は、ローカルコネクションに関する説明は既に詳しく行ったため、ソースコード中のコメントをもって解説と代えさせていただきたい。

    関連したタグ

    新着記事

    特設サイトの情報

      求人情報

      人気記事

      一覧

      イチオシ記事

      新着記事

      特別企画

      転職ノウハウ

      あなたの仕事適性診断

      4つの診断で、自分の適性を見つめなおそう!

      Heroes File ~挑戦者たち~

      働くこと・挑戦し続けることへの思いを綴ったインタビュー

      はじめての転職診断

      あなたにピッタリのアドバイスを読むことができます。

      転職Q&A

      転職に必要な情報が収集できます

      スカウト転職する

      企業からアプローチのメッセージが届きます。

      マイナビニュースマガジン