Search code examples
javascriptflashactionscriptexternalinterface

JavaScript talking to Flash via ExternalInterface


I have been trying to put together a proof of concept of JavaScript talking to Flash. I am using JQuery and Flash CS5, ActionScript 3.

I am not a Flash developer so apologies for the code, if I can prove this works the Flash will be given to someone who knows what they are doing.

The Actionscript is on a layer in the timeline in the first frame, with a couple of elements in the root movie:

output = new TextField();
output.y = -200;
output.x = -200;
output.width = 450;
output.height = 325;
output.multiline = true;
output.wordWrap = true;
output.border = true;
output.text = "Initializing...\n";
root.bgClip.addChild(output); 
try{
     Security.allowDomain("*");
     flash.external.ExternalInterface.marshallExceptions = true;
     output.appendText("External Interface Available? " + ExternalInterface.available + "\n");
     output.appendText("External Interface ObjectId: " + ExternalInterface.objectID + "\n");
     flash.external.ExternalInterface.addCallback("getMenuItems", returnMenuItems);
     flash.external.ExternalInterface.addCallback("changeText", changeText);
     flash.external.ExternalInterface.addCallback("changeBgColour", changeBgColour);
     flash.external.ExternalInterface.call("populateMenu", returnMenuItems());
} catch (error:SecurityError) {
    output.appendText("Security Error: " + error.message + "\n");
} catch (error:Error) {
    output.appendText("Error: " + error.message + "\n");
}
function returnMenuItems():String{
    return "[{\"menu option\": \"javascript:callFlash('changeBgColour','4CB9E4')\"}]";
}
function changeText(t:String){
    root.textClip.text = t;
}
function changeBgColour(colour:String) {
     var c:ColorTransform = root.bgClip.transform.colorTransform;
     c.color = uint(colour);
     root.bgClip.transform.colorTransform = c;
}

The JavaScript and HTML are:

function populateMenu(message){
    $("#options").changeType("Options", $.parseJSON(message));
    $("#options").addMenuActions();
}
function callFlash(methodToCall, param){
    alert("method: " + methodToCall + ", param: " + param);
    if(param == undefined){
        $("#AJC")[methodToCall]();
    }else{
        $("#AJC")[methodToCall](param);
    }
}
var flashvars = {};
var params = {allowScriptAccess: "always"};
var attributes = {name: "AJC"};
swfobject.embedSWF("http://192.168.184.128/ActionscriptJavascriptCommunication.swf", "AJC", "600", "400", "9", "", flashvars, params, attributes);

and

<body>
  <div id="wrapper">
    <div id="topBar" class="top-bar"></div>
    <div id="flashContainer">
      <div id="AJC">Loading Flash...</div>
    </div>
    <ul class="dropdown" id="games"></ul>
    <ul class="dropdown" id="options"></ul>
  </div>
</body>

Now I know the ActionScript is awful, the reason it looks like it does is because I have read a lot of threads about possible issues to do with contacting Flash from JavaScript (hence the allow security domain * and adding a debug text box etc).

The JavaScript I am using is within a script tag in the head. The changeType and addMenuActions are just JQuery methods I have added. These are just JavaScript methods that have been tested independently but do work.

You'll notice that the last line of my try catch in the ActionScript is:

flash.external.ExternalInterface.call("populateMenu", returnMenuItems());

This does work, it populate my menu with the text sent from Flash. The only thing that doesn't work is trying to call the methods exposed using the addCallback function.

I get the alert which says:

method: changeBgColour, param: 4CB9E4

but an error saying:

Error: $("#AJC")[methodToCall] is not a function
Source File: http://192.168.184.128/test.html#
Line: 88

I set up a local VM to run Apache, which relates to the 192.168.184.128, I wondering if this was the issue, I have seen a couple of threads mention that trying to communicate with flash locally won't work, which is why I set up the VM with apache?

Any ideas? I know people have got this working, it is very frustrating.

Thanks.


Solution

  • Simple mistake: jQuery's factory method produces jQuery.init object, which acts very similar to an array. You need to call the method on the actual DOM element, which is the first member in the "array".

    $('#AJC')[0][methodToCall]
    

    If you had security issues, you wouldn't be able to communicate between Flash and JavaScript at all.