Exempel på extern API: kommunicera mellan ActionScript och JavaScript i en webbläsare

Flash Player 9 och senare, Adobe AIR 1.0 och senare

I det här exempelprogrammet demonstreras lämpliga tekniker för kommunikation mellan ActionScript och JavaScript i en webbläsare, i det här fallet i ett snabbmeddelandeprogram som gör att en person kan chatta med sig själv (därav programnamnet: Introvert IM). Meddelanden skickas mellan ett HTML-formulär på webbsidan och ett SWF-gränssnitt med det externa API:t. Teknikerna som demonstreras i det här exemplet innehåller följande:

  • Initiera kommunikationen korrekt genom att verifiera att webbläsaren är klar att kommunicera innan kommunikationen startar

  • Kontrollera om behållaren stöder det externa API:t

  • Anropa JavaScript-funktioner från ActionScript, skicka parametrar och ta emot värden som svar

  • Göra ActionScript-metoder tillgängliga för anrop från JavaScript och utföra anropen

Programfilerna för det här exemplet finns på www.adobe.com/go/learn_programmingAS3samples_flash_se. Programfilerna för Introvert IM finns i mappen Samples/IntrovertIM_HTML. Programmet består av följande filer:

Fil

Beskrivning

IntrovertIMApp.fla

eller

IntrovertIMApp.mxml

Huvudprogramfilen för Flash (FLA) eller Flex (MXML).

com/example/programmingas3/introvertIM/IMManager.as

Klassen som upprättar och hanterar kommunikationen mellan ActionScript och behållaren.

com/example/programmingas3/introvertIM/IMMessageEvent.as

Anpassad händelsetyp som skickas av klassen IMManager när ett meddelande tas emot från behållaren.

com/example/programmingas3/introvertIM/IMStatus.as

En uppräkning vars värden representerar de olika värdena för tillgänglighetsstatus som kan väljas i programmet.

html-flash/IntrovertIMApp.html

eller

html-template/index.template.html

HTML-sidan för programmet för Flash (html-flash/IntrovertIMApp.html) eller den mall som används för att skapa HTML-behållarsidan för programmet för Adobe Flex (html-template/intex.template.html). Filen innehåller alla de JavaScript-funktioner som programmets behållardel består av.

Förberedelser för kommunikation mellan ActionScript och webbläsaren

Ett av de vanligaste sätten att använda det externa API:t är för att låta ActionScript-program kommunicera med en webbläsare. Med det externa API:t kan ActionScript-metoder anropa kod som skrivits i JavaScript och vice versa. Eftersom webbläsare är så komplicerade och eftersom de renderar sidor internt går det inte att garantera att ett SWF-dokument kan registrera sina callback-funktioner innan den första JavaScripten på HTML-sidan körs. Därför bör alltid SWF-dokumentet anropa HTML-sidan för att meddela den att SWF-dokumentet är klart att ta emot anslutningar innan funktionerna i SWF-dokumentet anropas från JavaScript.

Introvert IM avgör till exempel genom en serie steg som utförs av klassen IMManager om webbläsaren är klar för kommunikation och förbereder SWF-filen för kommunikation. Det första steget, som avgör när webbläsaren är klar för kommunikation, utförs i IMManager-konstruktorn på följande sätt:

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

Först kontrolleras om det externa API:t överhuvudtaget är tillgängligt i den aktuella behållaren med hjälp av egenskapen ExternalInterface.available. I så fall börjar kommunikationen upprättas. På grund av att säkerhetsundantag och andra fel kan uppstå när du försöker kommunicera med ett externt program är koden placerad i ett try-block (motsvarande catch-block har utelämnats i exemplet av utrymmesskäl).

Sedan anropas metoden isContainerReady() som listas här:

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

Metoden isContainerReady() använder i sin tur metoden ExternalInterface.call() för att anropa JavaScript-funktionen isReady() på följande sätt:

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

Funktionen isReady() returnerar helt enkelt värdet för variabeln jsReady. Den variabeln är från början false. När webbsidans onload-händelse aktiveras ändras variabelns värde till true. Med andra ord svarar JavaScript false på anropet ExternalInterface.call("isReady") om ActionScript anropar funktionen isReady() innan sidan har lästs in. Det gör i sin tur att ActionScript-metoden isContainerReady() returnerar false. När sidan har lästs in returnerar JavaScript-funktionen isReady()true så att även ActionScript-metoden isContainerReady() returnerar true.

I IMManager-konstruktorn händer en av två saker beroende på om behållaren är klar eller inte. Om isContainerReady() returnerar true anropar koden helt enkelt metoden setupCallbacks() som slutför processen att upprätta kommunikation med JavaScript. Om isContainerReady() å andra sidan returnerar false pausas i stället processen. Ett Timer-objekt skapas och instrueras att anropa metoden timerHandler() var hundrade millisekund på följande sätt:

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

Varje gång metoden timerHandler() anropas kontrollerar den resultatet av metoden isContainerReady(). När behållaren har initierats returnerar metoden true. Sedan stoppar koden Timer-objektet och anropar metoden setupCallbacks() som slutför processen att upprätta kommunikation med webbläsaren.

Exponera ActionScript-metoder för JavaScript

Föregående exempel visade, att när koden avgör att webbläsaren är klar, anropas metoden setupCallbacks(). Denna metod förbereder ActionScript för att ta emot anrop från JavaScript, vilket visas nedan:

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

Metoden setCallBacks() avslutar förberedelserna för kommunikation med behållaren genom att anropa ExternalInterface.addCallback() för att registrera de två metoder som ska vara tillgängliga för anrop från JavaScript. I den här koden är den första parametern – det namn som metoden är känd under i JavaScript ("newMessage" och "getStatus") – samma som metodens namn i ActionScript. (I det här fallet fanns det ingen fördel med att använda olika namn. Därför användes samma namn för enkelhetens skull.) Slutligen används metoden ExternalInterface.call() för att anropa JavaScript-funktionen setSWFIsReady(), som meddelar behållaren att ActionScript-funktionerna har registrerats.

Kommunikation från ActionScript till webbläsaren

Programmet Introvert IM demonstrerar ett antal exempel på hur JavaScript-funktioner anropas i behållarsidan. I det enklaste fallet (ett exempel från metoden setupCallbacks()) anropas JavaScript-funktionen setSWFIsReady() utan att några parametrar skickas och utan att något returvärde tas emot:

ExternalInterface.call("setSWFIsReady");

I ett annat exempel från metoden isContainerReady() anropar ActionScript funktionen isReady() och tar emot ett booleskt värde som svar:

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

Du kan också skicka parametrar till JavaScript-funktioner med det externa API:t. Ta till exempel metoden sendMessage() i klassen IMManager. Den anropas när användaren skickar ett nytt meddelande till sin ”konversationspartner”:

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

Återigen är det ExternalInterface.call() som används för att anropa den angivna JavaScript-funktionen och meddela webbläsaren om det nya meddelandet. Dessutom skickas själva meddelandet som en extra parameter till ExternalInterface.call(). Därmed skickas det även som en parameter till JavaScript-funktionen newMessage().

Anropa ActionScript-kod från JavaScript

Kommunikation ska ske åt två håll. Programmet Introvert IM är inget undantag. Det är inte bara Flash Players IM-klient som anropar JavaScript för att skicka meddelanden, HTML-formuläret anropar också JavaScript-koden för att skicka meddelanden till och få information från SWF-filen. När SWF-filen till exempel meddelar behållaren att den har upprättat kontakt och är klar att kommunicera, är det första webbläsaren gör att anropa metoden getStatus() i klassen IMManager för att hämta den ursprungliga statusen för användartillgänglighet från SWF-filens IM-klient. Detta görs i webbsidan med funktionen updateStatus() på följande sätt:

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

Koden kontrollerar värdet för variabeln swfReady, som håller reda på om SWF-filen har meddelat webbläsaren att den har registrerat sina metoder med klassen ExternalInterface. Om SWF-filen är klar att ta emot kommunikation anropar nästa rad (var currentStatus = ...) metoden getStatus() i klassen IMManager. Tre saker händer på den här kodraden:

  • JavaScript-funktionen getSWF() anropas och returnerar en referens till det JavaScript-objekt som representerar SWF-filen. Den parameter som skickas till getSWF() avgör vilket webbläsarobjekt som returneras om det finns mer än en SWF-fil i en HTML-sida. Det värde som skickas till den parametern måste matcha attributet id i object-taggen och attributet name i embed-taggen som används för att inkludera SWF-filen.

  • Med hjälp av referensen till SWF-filen anropas metoden getStatus() som om den vore en metod i SWF-objektet. I det här fallet används funktionsnamnet ”getStatus” eftersom det är namnet som ActionScript-funktionen är registrerad under med ExternalInterface.addCallback().

  • ActionScript-metoden getStatus() returnerar ett värde och det värdet tilldelas variabeln currentStatus, som sedan tilldelas som innehåll (egenskapen value) för textfältet status.

Obs! Om du följer koden märker du förmodligen att i källkoden för funktionen updateStatus() har kodraden som anropar funktionen getSWF() skrivits så här: var currentStatus = getSWF("${application}").getStatus(); Texten ${application} är en platshållare i HTML-sidmallen. När Adobe Flash Builder genererar den faktiska HTML-sidan för programmet, ersätts den här platshållaren med samma text som används som object-taggens id-attribut och embed-taggens name-attribut (IntrovertIMApp i exemplet). Det är värdet som förväntas av funktionen getSWF().

JavaScript-funktionen sendMessage() demonstrerar hur en parameter skickas till en ActionScript-funktion. (sendMessage() är den funktion som anropas när användaren trycker på knappen Send på HTML-sidan.)

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

ActionScript-metoden newMessage() förväntar sig en parameter, så JavaScript-variabeln message skickas till ActionScript genom att användas som parameter i anropet till metoden newMessage() i JavaScript-koden.

Identifiera webbläsartypen

Eftersom webbläsare öppnar innehåll på olika sätt är det viktigt att alltid använda JavaScript för att identifiera vilken webbläsare användaren har och att öppna filmen i enlighet med den webbläsarspecifika syntaxen, med objektet window eller document, vilket visas i JavaScript-funktionen getSWF() i det här exemplet:

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

Om skriptet inte kan identifiera användarens webbläsartyp kan användaren se oväntade effekter när SWF-filer spelas upp i en HTML-behållare.