While developing the YUI Charts, I discovered a nasty bug with ExternalInterface that affects many versions of Flash Player 9. Basically, it involves overwriting parts of the data passed from JavaScript somewhere in the encoding or decoding process. The best way to describe this error is to explain with an example.
Consider the following Flex application. Once it is initialized, the application calls a function named flashReady()
in the hosting page’s JavaScript. The function returns a complex object to display in the Flex app’s Tree control.
Source code for the Flex app:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="getDataFromJavaScript()"> <mx:HBox> <mx:Tree id="tree" width="250" height="300"/> <mx:TextArea id="parsedData" fontFamily="Courier New" fontSize="12" width="250" height="300"/> </mx:HBox> <mx:Label id="status" text="Loading Data..."/> <mx:Script> <![CDATA[ import com.adobe.serialization.json.JSON; private function getDataFromJavaScript():void { if(ExternalInterface.available) { var result:Object = ExternalInterface.call("flashReady", []); this.tree.dataProvider = result; //we're only encoding to JSON to view the result in the TextArea this.parsedData.text = JSON.encode(result); //version displayed for easy identification this.status.text = "Flash Player Version: " + Capabilities.version; } else { this.status.text = "ExternalInterface is not available!"; } } ]]> </mx:Script> </mx:Application>
The following structure is passed from JavaScript to ActionScript.
var dataToPass = { label: "Level 1-A", children: [ { label: "Level 2-A" }, { label: "Level 2-B", children: [ { label: "Level 3-A" }, { label: "Level 3-B" } ] }, { label: "Level 2-C", children: [ { label: "Level 3-C", children: [ { label: "Level 4-A" } ] }, { label: "Level 3-D" } ] } ] };
As you can see, the data passed through ExternalInterface has a complex hierarchy. Many of the objects have a label
variable and many have children
to specify branches in the Tree.
With Flash Player 9.0.28 (it affects other builds, but that one is commonly installed), the parsed data displayed in the TextArea control looks like the following code block. I’ve manually formatted it for readability.
{ "0" : { "label" : "Level 4-A" }, "children" : [ { "label" : "Level 4-A" } ], "1" : {"label" : "Level 3-D"}, "2" : { "0": { "label" : "Level 4-A" }, "children" : [ { "label" : "Level 4-A" } ], "1" : { "label" : "Level 3-D" }, "label" : "Level 3-D" }, "label" : "Level 3-D" }
You’ll notice that the label
property is overwritten on many of the more shallow levels. The strange numeric variables come from the indexes of the various children
Arrays. Clearly, much of the data gets completely lost. You can see the very nearly empty Tree control in the following screenshot.
Thankfully, Flash Player 9 Update 3 (build 9.0.115) properly handles this type of ExternalInterface data. However, one can hardly expect everyone to install the very newest version that isn’t even a month old yet.
For the YUI Charts, I needed to find a way to get around this problem in older versions of Flash Player 9. Using the YUI JSON Utility, I encoded the data provider and various other complex properties to simple strings before passing them through ExternalInterface from JavaScript to ActionScript. On the ActionScript side, the JSON data can be decoded with AS3 corelib to turn it back into native objects.
For public releases of Flash Player (official releases and those appearing on Adobe Labs), this bug seems to affect builds below 9.0.60 (the beta version of Update 3, mentioned above). It shouldn’t affect too many applications out there as ExternalInterface isn’t widely used, in my experience. For those out there that do make heavy use of this API, it’s definitely a concern, and you will either need to resort to encoding the data somehow or requiring FP 9.0.115 as the minimum version if you discover that you’re affected.
By the way, if you ever need to test older versions of Flash Player, Adobe provides nice zipped downloads of each major version (with multiple builds of each) back to Flash Player 2.