Monday, September 8, 2008

Code Review Vol. 6 - Injecting JavaScript from ActionScript

A project that I have been working on at my new company - which I will post about soon, I've just been waiting to take pictures so I can document how incredible the facilities are - is an ActionScript video player that allows us to play videos from multiple sources, including videos from vendors who require us to load in their player for the actual video playback. The external players, of course, require JavaScript to interact with them. In order to make my player self contained I needed a way to source the JavaScript directly from the ActionScript - this player is to used in a multitude of applications and projects company-wide and I couldn't guarantee that each project would have these necessary .js files.

I found this excellent article by Peter McBride - JavaScript and VBScript Injection in ActionScript 3

I based my solution off of the methodology in the article and it worked beautifully.

I created several AS classes, each with static public functions that could be invoked to load their respective JS into memory. Like the article describes, anonymous functions assigned to variables.


import flash.external.ExternalInterface;

public class JSONInjector
{
public function JSONInjector()
{
}

static public function registerPlayer():void
{
var js:XML = <script>
<![CDATA[
function()
{
JSPLAYER = new Object()
JSPLAYER.obs = {}; // Observers
JSPLAYER.addListener = function( eventType, callbackObj, callbackFunc){ .. }


Rsize = function(divID, height, width)
{
var element = document.getElementById(divID);
element.style.height = height + "px";
element.style.width = width + "px";
}

OpenNewWindow = function(URLtoOpen, windowName, windowFeatures)
{
var newWindow=window.open(URLtoOpen, windowName, windowFeatures);
}

...
}
]]>
</script>
try{
ExternalInterface.call(js);
}catch(e:Error){}

}



Then within the init of the main application I simply called the functions:


JSONInjector.registerContainer()
JSONInjector.registerPlayer()


And within my external interface files, I simply called the JS objects through external interface:


ExternalInterface.call("JSPLAYER.pause",true)


It's as simple as that, and now the need for any peripheral .js files has been negated and we have a self-contained solution for all video playback.

1 comment:

dean cadwallader said...

Fascinating stuff, i'm working on a desktop app in AIR that I want to detect the browser, current URL, and the size of the web-page, and store that info locally (as well as pass it to a database).

Maybe script-injecting would be a great way to action this :)