swfアプリからLingr APIのroom.observeを実行する

tyki2007-02-13


スマートじゃないとは思いつつ、実装そのものは難しくもなさそうなので、JavaScript経由でのリクエストを実際に試してみました。

  • swfからJavaScript経由でroom.observeのリクエスト(クロスドメインの制限によりswfからは直接GETできないため)
  • JSONPのコールバック関数経由でswfで結果を取得

という2点さえなんとかなれば、その他の機能はLingrサーバへのリクエストを仲介できるCGIに対してswfから直接POSTすればいいわけです。ということで、以下room.observeに絞って実験。

room.observeのリクエストに必要なパラメータは、

  • session(セッションID)
  • ticket(チケット)
  • counter(イベントカウンタ)

の3つ。いずれも最初に取得するのはPOSTでのリクエストの際になるので、swf側ですべて管理してしまった方がよさそう。そこで、JavaScript側はswfから渡されたパラメータをそのままLingr APIにパスするものとして実装してみます。

<script language="JavaScript" src="swfobject.js"></script>
<script language="JavaScript" src="odj.js"></script>
<script language="JavaScript">
  function thisMovie(movieName) {
    if (navigator.appName.indexOf("Microsoft") != -1) {
      return window[movieName];
    } else {
      return document[movieName];
    }
  }
  function doObserve(sid, ticket, cnt) {
    var url = 'http://www.lingr.com/api/room/observe/'
      + '?format=json&session=' + sid + '&ticket=' + ticket + '&counter=' + cnt;
    var oOdj = new onDemandJavaScript();
    oOdj.request(url, getObserveResult, 'callback');
  }
  function getObserveResult(r) {
    alert(r.messages[0].text);
    thisMovie('roomObserveTestSWF').flexCallBack(r.messages[0].text, r.counter);
  }
</script>
<div id="flashcontent"></div>

<script language="JavaScript">
  var so = new SWFObject("rotest.swf", "roomObserveTestSWF", "500", "300", "7", "#336699");
  so.addParam('allowScriptAccess', 'always');
  so.write("flashcontent");
</script>

今回、JSONPの扱いにはkyo氏のodj.js(onDemandJavaScriptクラス)を利用させて頂きました。

ActionScript側も単純で、initializeのタイミングでExternalInterface.addCallbackでjs側から呼び出せるコールバック関数を設定し、ExternalInterface.callでjs側の関数を実行するだけ。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="initApp()">
    <mx:Script>
        <![CDATA[
            import mx.controls.*;
            import flash.external.*;

            public function initApp():void {
                ExternalInterface.addCallback("flexCallBack", getObserveResult);
            }
            public function getObserveResult(r:String, c:String):void {
                Alert.show(r);
                counter.text = c;
            }
            public function startObserve():void {
                ExternalInterface.call("doObserve", session.text, ticket.text, counter.text);
            }
        ]]>
    </mx:Script>
    <mx:Panel title="Lingr API Test" width="100%" height="100%" id="main_panel"
            paddingTop="10" paddingBottom="10" paddingLeft="10" paddingRight="10">
        <mx:Form width="100%" height="100%">
            <mx:FormHeading label="Enter parameters into the form below"/>
            <mx:FormItem label="session">
                <mx:TextInput id="session" width="200"/>
            </mx:FormItem>
            <mx:FormItem label="ticket">
                <mx:TextInput id="ticket" width="200"/>
            </mx:FormItem>
            <mx:FormItem label="counter">
                <mx:TextInput id="counter" width="200"/>
            </mx:FormItem>
        </mx:Form>
        <mx:Button label="Start Observe Room" click="startObserve()" />
    </mx:Panel>
</mx:Application>

本当はExternalInterface.addCallbackの前にjs側の準備が整ったかどうかチェックするべきですが、面倒なので今回はばっさり省略。後はmxmlcでswfにコンパイルしてHTMLを開き、フォームに別の手段で確保した3引数を入れてボタンを押せば発言が一個ずつ取れます。

思ったよりシンプルなソースで実現できたものの、ローカル環境では動作しなくて随分詰まりました。allowScriptAccessはちゃんとalwaysにしてるし、何でだろう‥‥