Beispiel für externe API: Kommunikation zwischen ActionScript und JavaScript in einem Webbrowser

Flash Player 9 und höher, Adobe AIR 1.0 und höher

Diese Beispielanwendung veranschaulicht geeignete Techniken für den Datenaustausch zwischen ActionScript und JavaScript in einem Webbrowser im Kontext einer Instant Messaging-Anwendung, die es einer Person ermöglicht, mit sich selbst zu chatten (daher der Name der Anwendung: Introvert IM). Nachrichten werden mithilfe der externen API zwischen einem in die Webseite integrierten HTML-Formular und einer SWF-Benutzeroberfläche ausgetauscht. In diesem Beispiel werden folgende Techniken demonstriert:

  • Ordnungsgemäßes Initiieren des Datenaustauschs durch Überprüfen, ob der Browser bereit ist, bevor ein Datenaustausch gestartet wird

  • Überprüfen, ob der Container die externe API unterstützt

  • Aufrufen von JavaScript-Funktionen aus ActionScript, Übergeben von Parametern und Empfangen von Rückgabewerten

  • Verfügbarmachen von ActionScript-Methoden für Aufrufe aus JavaScript und Ausführen dieser Aufrufe

Die Anwendungsdateien für dieses Beispiel finden Sie unter www.adobe.com/go/learn_programmingAS3samples_flash_de . Die Dateien der Anwendung „Introvert IM“ befinden sich im Ordner „Samples/IntrovertIM_HTML“. Die Anwendung umfasst die folgenden Dateien:

Datei

Beschreibung

IntrovertIMApp.fla

oder

IntrovertIMApp.mxml

Die Hauptanwendungsdatei im Flash-Format (FLA) oder Flex-Format (MXML).

com/example/programmingas3/introvertIM/IMManager.as

Die Klasse, mit der der Datenaustausch zwischen ActionScript und dem Container aufgebaut und verwaltet wird.

com/example/programmingas3/introvertIM/IMMessageEvent.as

Ein benutzerdefinierter Ereignistyp, der von der IMManager-Klasse ausgelöst wird, wenn eine vom Container stammende Nachricht empfangen wurde.

com/example/programmingas3/introvertIM/IMStatus.as

Eine Aufzählung, deren Werte die verschiedenen Statuswerte für die „Verfügbarkeit“ angeben, die in der Anwendung ausgewählt werden kann.

html-flash/IntrovertIMApp.html

oder

html-template/index.template.html

Für Flash die HTML-Seite der Anwendung (html-flash/IntrovertIMApp.html) oder für Adobe Flex die Vorlage, die zum Erstellen der Container-HTML-Seite der Anwendung verwendet wird (html-template/index.template.html). Diese Datei enthält alle JavaScript-Funktionen der Containerkomponente der Anwendung.

Vorbereiten der Kommunikation mit dem ActionScript-Browser

Einer der häufigsten Einsatzzwecke für die externe API ist der Datenaustausch zwischen ActionScript-Anwendungen und einem Webbrowser. Mithilfe der externen API kann mit ActionScript-Methoden JavaScript-Code aufgerufen werden und umgekehrt. Aufgrund der Komplexität von Browsern und der Art, wie diese Seiten intern darstellen, gibt es keine Möglichkeit sicherzustellen, dass ein SWF-Dokument die zugehörigen Callback-Funktionen registriert hat, bevor die erste JavaScript-Anweisung in der HTML-Seite ausgeführt wird. Aus diesem Grund sollte das SWF-Dokument stets zuerst die HTML-Seite aufrufen und darüber benachrichtigen, dass es verbindungsbereit ist, bevor aus JavaScript Funktionen des SWF-Dokuments aufgerufen werden.

In der Anwendung „Introvert IM“ wird beispielsweise durch eine Reihe von Schritten in der IMManager-Klasse ermittelt, ob der Browser für den Datenaustausch bereit ist, und die SWF-Datei dann darauf vorbereitet. Der erste Schritt – Ermitteln, ob der Browser für den Datenaustausch bereit ist – erfolgt im IMManager-Konstruktor:

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."); 
    } 
}

Zunächst wird mithilfe der ExternalInterface.available -Eigenschaft überprüft, ob die externe API im aktuellen Container überhaupt verfügbar ist. Wenn dies der Fall ist, beginnt der Aufbau der Kommunikation. Da beim Kommunikationsaufbau mit externen Anwendungen Sicherheitsausnahmen und andere Fehler auftreten können, ist der Code in einen try -Block eingeschlossen. (Die entsprechenden catch -Blöcke sind aus Platzgründen nicht aufgeführt.)

Anschließend wird die im Folgenden aufgeführte isContainerReady() -Methode aufgerufen:

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

Die isContainerReady() -Methode verwendet wiederum wie folgt die ExternalInterface.call() -Methode, um die JavaScript-Funktion isReady() aufzurufen:

<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>

Die isReady() -Funktion gibt den Wert der Variablen jsReady zurück. Diese Variable erhält zu Anfang den Wert false . Nachdem das onload -Ereignis der Webseite ausgelöst wurde, ist der Wert der Variablen true . Mit anderen Worten: Wenn ActionScript die isReady() -Funktion aufruft, bevor die Seite geladen ist, gibt JavaScript beim Aufruf von ExternalInterface.call("isReady") den Wert false zurück. Daraufhin gibt auch die ActionScript-Methode isContainerReady() den Wert false zurück. Nachdem die Seite geladen wurde, gibt die JavaScript-Funktion isReady() den Wert true zurück, daraufhin gibt auch die ActionScript-Methode isContainerReady den Wert true zurück.

Je nach Bereitschaft des Containers werden im IMManager-Konstruktor zwei verschiedene Aktionen ausgeführt. Wenn isContainerReady() den Wert true zurückgibt, wird die setupCallbacks() -Methode aufgerufen, die den Aufbau der Kommunikation mit JavaScript abschließt. Wenn isContainerReady() jedoch false zurückgibt, wird der Vorgang vorerst ausgesetzt. Es wird wie folgt ein Timer-Objekt erstellt, das alle 100Millisekunden die timerHandler() -Methode aufrufen soll:

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(); 
    } 
}

Bei jedem Aufruf der timerHandler() -Methode wird erneut das Ergebnis der isContainerReady() -Methode überprüft. Wenn der Container initialisiert ist, gibt diese Methode Folgendes zurück: true. Daraufhin wird der Timer angehalten und die setupCallbacks() -Methode aufgerufen, um den Aufbau der Kommunikation mit dem Browser abzuschließen.

Bereitstellen von ActionScript-Methoden für JavaScript

Wie im vorangegangenen Beispiel gezeigt wurde, wird die setupCallbacks() -Methode aufgerufen, nachdem ermittelt wurde, dass der Browser bereit ist. Mit dieser Methode wird ActionScript wie folgt darauf vorbereitet, Aufrufe aus JavaScript zu empfangen:

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"); 
}

Die setCallBacks() -Methode schließt die Vorbereitung der Kommunikation mit dem Container ab, indem ExternalInterface.addCallback() aufgerufen wird, um die beiden Methoden zu registrieren, die für den Aufruf aus JavaScript verfügbar sein sollen. Im Codebeispiel stimmt der erste Parameter – der Name, unter dem die Methode in JavaScript bekannt ist ( „newMessage" und „getStatus" ) – mit dem Namen der Methode in ActionScript überein. (In diesem Fall brachte es keine Vorteile, unterschiedliche Namen zu verwenden, deshalb wurde aus Gründen der Einfachheit derselbe Name verwendet.) Schließlich wird die ExternalInterface.call() -Methode verwendet, um die JavaScript-Funktion setSWFIsReady() aufzurufen, die den Container darüber benachrichtigt, dass die ActionScript-Funktionen nun registriert sind.

Datenübertragung von ActionScript zum Browser

In der Anwendung „Introvert IM“ werden viele Beispiele für das Aufrufen von JavaScript-Funktionen in der Containerseite vorgestellt. Im einfachsten Fall (ein Beispiel aus der setupCallbacks() -Methode) wird die JavaScript-Funktion setSWFIsReady() aufgerufen, ohne dass Parameter übergeben oder ein Rückgabewert zurückgegeben wird:

ExternalInterface.call("setSWFIsReady");

In einem anderen Beispiel aus der isContainerReady() -Methode ruft ActionScript die isReady() -Funktion auf und erhält als Rückgabewert einen booleschen Wert:

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

Sie können mithilfe der externen API auch Parameter an JavaScript-Funktionen übergeben. Dies erfolgt beispielsweise mit der sendMessage() -Methode der IMManager-Klasse, die aufgerufen wird, wenn der Benutzer eine neue Nachricht an den „Gesprächspartner“ sendet:

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

Wieder wird ExternalInterface.call() verwendet, um die entsprechende JavaScript-Funktion aufzurufen, mit der der Browser über die neue Nachricht informiert wird. Zusätzlich wird die Nachricht selbst als weiterer Parameter an ExternalInterface.call() übergeben und dann als Parameter an die JavaScript-Funktion newMessage() weitergeleitet.

Aufrufen von ActionScript-Code aus JavaScript

Eine wirkliche Kommunikation findet erst statt, wenn der Datenaustausch in beide Richtungen erfolgt, und die Anwendung „Introvert IM“ stellt dabei keine Ausnahme dar. Nicht nur der Flash Player-IM-Client ruft JavaScript-Funktionen auf, um Nachrichten zu senden, sondern auch das HTML-Formular verwendet JavaScript, um Nachrichten an die SWF-Datei zu senden und Informationen abzufragen. Wenn beispielsweise die SWF-Datei den Container benachrichtigt, dass die Kontaktaufnahme abgeschlossen und Kommunikationsbereitschaft hergestellt ist, ruft der Browser zunächst die getStatus() -Methode der IMManager-Klasse auf, um vom SWF-IM-Client den Anfangsstatus der Benutzerverfügbarkeit abzurufen. Dies erfolgt mithilfe der updateStatus() -Funktion in der Webseite:

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

Es wird der Wert der Variablen swfReady überprüft, in der gespeichert ist, ob die SWF-Datei den Browser darüber benachrichtigt hat, dass die Methoden nun bei der ExternalInterface-Klasse registriert sind. Wenn die SWF-Datei kommunikationsbereit ist, wird mit der nächsten Zeile ( var currentStatus = ...) die getStatus() -Methode der IMManager-Klasse aufgerufen. In dieser Codezeile werden drei Vorgänge durchgeführt:

  • Die JavaScript-Funktion getSWF() wird aufgerufen, die einen Verweis auf das JavaScript-Objekt zurückgibt, mit dem die SWF-Datei angegeben wird. Mit dem an getSWF() übergebenen Parameter wird festgelegt, welches Browserobjekt zurückgegeben wird, wenn pro HTML-Seite mehrere SWF-Dateien vorhanden sind. Der Wert dieses Parameters muss mit dem id -Attribut des object -Tags und dem name -Attribut des embed -Tags übereinstimmen, die zum Einfügen der SWF-Datei verwendet wurden.

  • Mithilfe des Verweises auf die SWF-Datei wird die getStatus() -Methode aufgerufen, als wäre sie eine Methode des SWF-Objekts. In diesem Fall wird der Funktionsname getStatus verwendet, da die ActionScript-Funktion mithilfe von ExternalInterface.addCallback() unter diesem Namen registriert wurde.

  • Die ActionScript-Methode getStatus() gibt einen Wert zurück. Dieser Wert wird der Variablen currentStatus zugewiesen, die dann als Inhalt des Textfelds status (über die value -Eigenschaft) zugewiesen wird.

Hinweis: Wenn Sie den Code mitverfolgt haben, ist Ihnen wahrscheinlich aufgefallen, dass im Quellcode für die Funktion updateStatus() die Codezeile, die die Funktion getSWF() aufruft, folgendermaßen geschrieben ist: var currentStatus = getSWF("${application}").getStatus(); Der Text ${application} ist ein Platzhalter in der HTML-Seitenvorlage. Wenn Adobe Flash Builder die tatsächliche HTML-Seite für die Anwendung generiert, wird dieser Platzhalter durch den Text ersetzt, der für das object -Tag als id -Attribut und für das embed -Tag als name -Attribut verwendet wird (in diesem Beispiel IntrovertIMApp ). Dies ist der Wert, der von der getSWF() -Funktion erwartet wird.

Die JavaScript-Funktion sendMessage() veranschaulicht das Übergeben von Parametern an eine ActionScript-Funktion. (Die sendMessage() -Funktion wird aufgerufen, wenn der Benutzer auf der HTML-Seite auf die Schaltfläche „Send“ klickt.)

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

Die ActionScript-Methode newMessage() erwartet einen Parameter, deshalb wird die JavaScript-Variable message an ActionScript übergeben, indem sie im JavaScript-Code beim Aufruf der newMessage() -Methode als Parameter verwendet wird.

Erkennen des Browsertyps

Aufgrund der browserspezifischen Unterschiede beim Zugriff auf Inhalte ist es wichtig, immer den vom Benutzer verwendeten Browser zu ermitteln und auf den Film der jeweiligen Syntax entsprechend zuzugreifen. Dies erfolgt mithilfe von JavaScript und des Window- oder Document-Objekts, wie in der JavaScript-Funktion getSWF() in diesem Beispiel dargestellt ist:

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

Wenn der Browsertyp des Benutzers im Skript nicht erkannt wird, kann es bei der Wiedergabe von SWF-Dateien in einem HTML-Container zu unerwartetem Verhalten kommen.