Full JavaScript Access From ActionScript (update)

Have you ever tought about accessing DOM from ActionScript? In fact, you can do it and even far more. You can create and call JavaScript methods and objects, access cookies, change styles… All you need is correct AllowScriptAccess parameter within your flash object. No framework needed here, no hacks, ExternalInterface takes care.

Following application runs JavaScript from textarea:

Application. Line 16 does all the fun 🙂

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    applicationComplete="init()">
<mx:Script>
<![CDATA[
    [Bindable]
    private var lastResult:String = "";
    
    private function init():void
    {
        ExternalInterface.addCallback("universalCallback", universalCallback);
    }
    
    private function runScript():void
    {
        ExternalInterface.call("eval", script.text);
    }
    
    private function universalCallback(... rest):void
    {
        lastResult = String(rest[0]);
    }
]]>
</mx:Script>
<mx:HBox width="100%" height="100%">
    <mx:TextArea id="script" width="100%" height="100%">
        <mx:text>
            <![CDATA[
function myFunction(){
    var flash = document.getElementById("flash");
    var data = document.childNodes[1].innerHTML;
    flash.universalCallback(data);
}

myFunction();
alert(document.getElementsByTagName('title')[0].innerHTML);
            ]]>
        </mx:text>
    </mx:TextArea>
    <mx:TextArea width="100%" height="100%" text="{lastResult}" />
</mx:HBox>

<mx:Button click="runScript()" label="Run"/>
</mx:Application>

HTML template

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"> 
<head> 
    <title>Full Javascript Access</title> 
    <meta http-equiv="Content-Type" content="application/xml; charset=utf-8" /> 
    <meta http-equiv="Cache-Control" content="no-cache" /> 
    <meta http-equiv="expires" content="1" /> 
    <meta http-equiv="pragma" content="no-cache" /> 
    
    <meta name="author" content="http://studio.yoz.sk" /> 
    <meta name="description" content="Full Javascript Access" /> 
    <meta name="robots" content="all" /> 
    
    <script type="text/javascript" src="js/swfobject.js"></script>
    <script type="text/javascript">
    <!--
        var flashvars = {}
        
        var params = {
            allowscriptaccess: "always"
        };
        var attributes = {
            id: "flash",
            name: "flash"
        };
        swfobject.embedSWF("Tests.swf", "alternative", "100%", "100%", "10.0.0",
            "flash/expressInstall.swf", flashvars, params, attributes);
    //-->
    </script>
    
    <style type='text/css'> 
    <!--
        body {margin:0px;overflow:hidden;}
        html, body, object, embed {width:100%;height:100%;outline:none;}
    -->
    </style>
</head> 
<body>
    <div id="alternative"> 
        <a href="http://www.adobe.com/go/getflashplayer"> 
            <img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" /> 
        </a> 
    </div>
</body> 
</html>

No additional nothing here just:

  • line 20: allowscriptaccess: “always” (“sameDomain” may also be used)
  • line 24: tip – add name attribute with swfobject so ExternalInterface.objectID will get correct value

Considerations of using eval:

  • Improper use of eval opens up your code for injection attacks
  • Debugging can be more challenging (no line numbers, etc.)
  • eval’d code executes more slowly (no opportunity to compile/cache eval’d code)

Update (Feb 11, 2010): You can use either eval call:

ExternalInterface.call("eval", script.text);

or wrap your script into anonymous function:

ExternalInterface.call("function(){" + script.text + "}");

Personally, I do not see any difference in execution, it seems to be the same, maybe some performance testing would clarify it. What do you think?

Where to go from here:

4 comments so far

  1. anonymouse August 17, 2010 08:04

    You can also use the mxml String tag to place your script in it:

  2. anonymouse August 17, 2010 08:05

    Comment eaten. Round 2:

  3. anonymouse August 17, 2010 08:06

    Comment eaten again. Round 3:

    < fx:String id=”script”>< ![CDATA[

    function myFunction(){
    var flash = document.getElementById(“APICheck”);
    var data = document.childNodes[1].innerHTML;
    flash.universalCallback(data);
    }
    ]] >< /fx:String>

  4. anonymouse August 17, 2010 09:01

    FYI – if you have a linebreak character then it will break your script. IE this code, “\n” needs to be changed to “\\n”

Leave a comment

Please be polite and on topic. Your e-mail will never be published.