External API の例:Web ブラウザーでの ActionScript と JavaScript との通信

Flash Player 9 以降、Adobe AIR 1.0 以降

このサンプルアプリケーションでは、ユーザーが自分自身とチャットできる Instant Messaging アプリケーションの場合に、Web ブラウザー内で ActionScript と JavaScript が通信するための方法を示しています(アプリケーション名: Introvert IM)。 メッセージは External API を使用して、Web ページ内の HTML 形式と SWF インターフェイスとの間で送信されます。 この例で示す方法では、次のことを行います。

  • ブラウザーが通信可能なことを確認してから通信を設定することによる、通信の正しい初期化

  • コンテナが External API をサポートしているかどうかの確認

  • ActionScript からの JavaScript 関数の呼び出し、パラメーターの受け渡し、および応答による値の受け取り

  • JavaScript から呼び出される ActionScript メソッドの有効化、および呼び出しの実行

このサンプルのアプリケーションのファイルを入手するには、 www.adobe.com/go/learn_programmingAS3samples_flash_jp を参照してください。 Introvert IM アプリケーションのファイルは、Samples/IntrovertIM_HTML フォルダーにあります。 このアプリケーションは次のファイルで構成されています。

ファイル

説明

IntrovertIMApp.fla

または

IntrovertIMApp.mxml

Flash(FLA)または Flex(MXML)のメインアプリケーションファイル。

com/example/programmingas3/introvertIM/IMManager.as

ActionScript とコンテナとの間の通信を確立および管理するクラス。

com/example/programmingas3/introvertIM/IMMessageEvent.as

コンテナからメッセージを受信したときに IMManager クラスから送出されるカスタムイベントタイプ。

com/example/programmingas3/introvertIM/IMStatus.as

アプリケーションで選択可能な、様々な「availability」ステータス値を値が表している列挙。

html-flash/IntrovertIMApp.html

または

html-template/index.template.html

Flash アプリケーションの HTML ページ(html-flash/IntrovertIMApp.html)または Adobe Flex アプリケーションのコンテナ HTML ページ作成に使用するテンプレート(html-template/index.template.html)。 このファイルには、アプリケーションのコンテナ部分を構成するすべての JavaScript 関数が格納されています。

ActionScript とブラウザー間の通信の準備

External API の最も一般的な用途の 1 つは、ActionScript アプリケーションと Web ブラウザーとの通信です。 External API を使用すると、ActionScript メソッドから JavaScript コードへの呼び出し、および JavaScript コードから ActionScript メソッドへの呼び出しを実現できます。 ブラウザーの仕組みは複雑であり、また、ブラウザー内部で実行されるページレンダリング処理が不明であることから、HTML ページ上の JavaScript コードが最初に実行される前に SWF ドキュメントのコールバックを登録できる保証はありません。 したがって、JavaScript から SWF ドキュメントの関数を呼び出す前に、SWF ドキュメント側の接続受け付け準備ができたことを通知するために、必ず SWF ドキュメントから HTML ページへの呼び出しを実行してください。

例えば、IMManager クラスで実行される一連の手順によって、ブラウザーの通信準備ができ、SWF ファイルを通信で使用できることが、Introvert IM で判定されます。 ブラウザーの通信準備ができたことを判定する最初の手順は、次のように IMManager コンストラクターで実行されます。

public function IMManager(initialStatus:IMStatus) 
{ 
    _status = initialStatus; 
 
    // Check if the container is able to use the external API. 
    if (ExternalInterface.available) 
    { 
        try 
        { 
            // This calls the isContainerReady() method, which in turn calls 
            // the container to see if Flash Player has loaded and the container 
            // is ready to receive calls from the SWF. 
            var containerReady:Boolean = isContainerReady(); 
            if (containerReady) 
            { 
                // If the container is ready, register the SWF's functions. 
                setupCallbacks(); 
            } 
            else 
            { 
                // If the container is not ready, set up a Timer to call the 
                // container at 100ms intervals. Once the container responds that 
                // it's ready, the timer will be stopped. 
                var readyTimer:Timer = new Timer(100); 
                readyTimer.addEventListener(TimerEvent.TIMER, timerHandler); 
                readyTimer.start(); 
            } 
        } 
        ... 
    } 
    else 
    { 
        trace("External interface is not available for this container."); 
    } 
}

最初に、このコードは ExternalInterface.available プロパティを使用して、External API が現在のコンテナで利用可能かどうかをチェックします。利用可能であれば、通信の設定手順が開始されます。 外部アプリケーションと通信しようとするとセキュリティ例外やその他のエラーが発生することがあるため、コードは try ブロックでラップされています(簡単にするため、対応する catch ブロックは省略されています)。

次に、ここに示すように isContainerReady() メソッドが呼び出されます。

private function isContainerReady():Boolean 
{ 
    var result:Boolean = ExternalInterface.call("isReady"); 
    return result; 
}

isContainerReady() メソッドは、 ExternalInterface.call() メソッドを使用して次のように JavaScript 関数 isReady() を呼び出します。

<script language="JavaScript"> 
<!-- 
// ------- Private vars ------- 
var jsReady = false; 
... 
// ------- functions called by ActionScript ------- 
// called to check if the page has initialized and JavaScript is available 
function isReady() 
{ 
    return jsReady; 
} 
... 
// called by the onload event of the <body> tag 
function pageInit() 
{ 
    // Record that JavaScript is ready to go. 
    jsReady = true; 
} 
... 
//--> 
</script>

isReady() 関数は、単純に jsReady 変数の値を返します。この変数の初期値は false です。Web ページの onload イベントがトリガーされると、変数の値が true に変化します。つまり、ページのロード前に ActionScript から isReady() 関数が呼び出されると、JavaScript から ExternalInterface.call("isReady") false が返され、その結果 ActionScript isContainerReady() メソッドから false が返されます。ページがロードされると、JavaScript isReady() 関数から true が返されるため、ActionScript isContainerReady() メソッドからも true が返されます。

IMManager コンストラクターでは、コンテナの準備状態に応じて 2 つのことが行われます。 isContainerReady() から true が返された場合は、コードから単純に setupCallbacks() メソッドが呼び出されて、JavaScript での通信の設定手順が完了します。一方、 isContainerReady() から false が返された場合、手順は実質的に保留状態になります。Timer オブジェクトが作成され、次のように 100 ミリ秒間隔で timerHandler() メソッドを呼び出すよう指示されます。

private function timerHandler(event:TimerEvent):void 
{ 
    // Check if the container is now ready. 
    var isReady:Boolean = isContainerReady(); 
    if (isReady) 
    { 
        // If the container has become ready, we don't need to check anymore, 
        // so stop the timer. 
        Timer(event.target).stop(); 
        // Set up the ActionScript methods that will be available to be 
        // called by the container. 
        setupCallbacks(); 
    } 
}

timerHandler() メソッドが呼び出されるたびに、 isContainerReady() メソッドの結果が再確認されます。コンテナが初期化されると、このメソッドから true が返されます。次に、コードでは Timer を停止して setupCallbacks() メソッドを呼び出し、ブラウザーの通信の設定手順を終了します。

JavaScript への ActionScript メソッドの公開

上記の例で示したように、ブラウザーの準備ができたことがコードで判定されると、 setupCallbacks() メソッドが呼び出されます。このメソッドでは、次のように JavaScript からの呼び出しを受信するよう ActionScript が準備されます。

private function setupCallbacks():void 
{ 
    // Register the SWF client functions with the container 
    ExternalInterface.addCallback("newMessage", newMessage); 
    ExternalInterface.addCallback("getStatus", getStatus); 
    // Notify the container that the SWF is ready to be called. 
    ExternalInterface.call("setSWFIsReady"); 
}

setCallBacks() メソッドは、 ExternalInterface.addCallback() を呼び出して JavaScript から呼び出し可能な 2 つのメソッドを登録することにより、コンテナとの通信準備のタスクを終了します。このコードでは、ActionScript のメソッド名と同じ名前が第 1 パラメーターになっています。JavaScript(「 newMessage 」および「 getStatus 」)は、この名前によってメソッドを認識します(この場合、異なる名前を使用することに意味がないため、同じ名前を再利用しました)。 最後に、 ExternalInterface.call() メソッドを使用して JavaScript 関数 setSWFIsReady() が呼び出され、ActionScript 関数の登録されたコンテナが通知されます。

ActionScript からブラウザーへの通信

Introvert IM アプリケーションは、コンテナページでの JavaScript 関数の呼び出しに関する様々な例を示しています。 最も単純な場合( setupCallbacks() メソッドの例)には、パラメーターを渡したり、返される値を受け取ったりすることなく、JavaScript 関数 setSWFIsReady() が呼び出されます。

ExternalInterface.call("setSWFIsReady");

isContainerReady() メソッドの別の例では、ActionScript から isReady() 関数が呼び出され、それに対する応答としてブール値を受け取ります。

var result:Boolean = ExternalInterface.call("isReady");

External API を使用して JavaScript 関数にパラメーターを渡すこともできます。 例えば、IMManager クラスの sendMessage() メソッドについて考えてみます。このメソッドは、ユーザーが自分の「交信パートナー」に新しいメッセージを送信するときに呼び出されます。

public function sendMessage(message:String):void 
{ 
    ExternalInterface.call("newMessage", message); 
}

ここでも、指定された JavaScript 関数が ExternalInterface.call() を使用して呼び出され、ブラウザーに新しいメッセージが通知されます。また、メッセージ自身は ExternalInterface.call() の追加パラメーターとして渡され、結果的に JavaScript 関数 newMessage() のパラメーターとして渡されます。

JavaScript からの ActionScript コードの呼び出し

通信は双方向形式でサポートされ、Introvert IM アプリケーションも例外ではありません。 Flash Player IM クライアントがメッセージ送信のために JavaScript を呼び出すだけでなく、HTML フォームも JavaScript コードを呼び出して、メッセージを SWF ファイルに送信したり、SWF ファイルに情報を問い合わせます。 例えば、接続が完了し、通信準備ができたことを SWF ファイルがコンテナに通知する場合、ブラウザーが最初に行うことは、IMManager クラスの getStatus() メソッドを呼び出して、初期のユーザー availability ステータスを SWF IM クライアントから受信することです。これは、次のように Web ページの updateStatus() 関数で行われます。

<script language="JavaScript"> 
... 
function updateStatus() 
{ 
    if (swfReady) 
    { 
        var currentStatus = getSWF("IntrovertIMApp").getStatus(); 
        document.forms["imForm"].status.value = currentStatus; 
    } 
} 
... 
</script>

このコードでは、 swfReady 変数の値が確認されます。この変数により、SWF ファイルのメソッドが ExternalInterface クラスに登録されたことが SWF ファイルからブラウザーに通知されたかどうかが追跡されます。SWF ファイルで通信の受信準備ができている場合、その次の行( var currentStatus = ... )では実際に IMManager クラスの getStatus() メソッドが呼び出されます。コードのこの行では、次の 3 つのことが行われます。

  • getSWF() JavaScript 関数が呼び出され、SWF ファイルを表す JavaScript オブジェクトへの参照が返されます。 getSWF() に渡されたパラメーターによって、HTML ページ内に複数の SWF ファイルが存在する場合にどのブラウザーオブジェクトが返されるかが決まります。このパラメーターに渡される値は、 object タグの id 属性、および SWF ファイルの埋め込みに使用される embed タグの name 属性と一致している必要があります。

  • SWF ファイルへの参照を使用することで、SWF オブジェクトのメソッドであるかのように getStatus() メソッドが呼び出されます。この場合、関数名「 getStatus 」が使用されるのは、 ExternalInterface.addCallback() を使用して ActionScript 関数がこの名前で登録されるからです。

  • getStatus() ActionScript メソッドでは値が返され、その値が currentStatus 変数に割り当てられて、それがさらに status テキストフィールドのコンテンツ( value プロパティ)として割り当てられます。

注意: このコードをたどると、 updateStatus() 関数のソースコードでは、 getSWF() 関数を呼び出すコードの行が実際は次のように書かれていることがわかります。var currentStatus = getSWF("${application}").getStatus(); ${application} というテキストは、HTML ページ テンプレートのプレースホルダーです。Adobe Flex Builder が実際の HTML ページを生成する場合、このプレースホルダーのテキストは、 object タグの id 属性および embed タグの name 属性(この例では、 IntrovertIMApp )として使用されているテキストと同じテキストによって置き換えられます。これは getSWF() 関数に必要な値です。

sendMessage() JavaScript 関数は、ActionScript 関数へのパラメーターの受け渡しを示しています( sendMessage() は、ユーザーが HTML ページの「送信」ボタンを押したときに呼び出される関数です)。

<script language="JavaScript"> 
... 
function sendMessage(message) 
{ 
    if (swfReady) 
    { 
        ... 
        getSWF("IntrovertIMApp").newMessage(message); 
    } 
} 
... 
</script>

newMessage() ActionScript メソッドにはパラメーターが 1 つ必要なため、JavaScript コード内の newMessage() メソッドの呼び出しで JavaScript message 変数をパラメーターとして使用することで、この変数が ActionScript に渡されます。

ブラウザータイプの検出

ブラウザーがコンテンツにアクセスする方法は様々であるため、この例の getSWF() JavaScript 関数に示すように、必ず JavaScript を使用してユーザーが実行しているブラウザーを検出すること、およびウィンドウまたはドキュメントオブジェクトを使用して、ブラウザー固有のシンタックスに従ってムービーにアクセスすることが重要です。

<script language="JavaScript"> 
... 
function getSWF(movieName) 
{ 
    if (navigator.appName.indexOf("Microsoft") != -1) 
    { 
        return window[movieName]; 
    } 
    else 
    { 
        return document[movieName]; 
    } 
} 
... 
</script>

スクリプトによってユーザーのブラウザータイプが検出されない場合、HTML コンテナの SWF ファイルを再生したときに予期しない動作が発生することがあります。