Why does ExternalInterface breaks when I pass parameter with JSON like string?

8.2k views Asked by At

I have a very odd problem with Flash 10 and ExternalInterface. I am currently using a homemade bridge to use RTMFP with Javascript and whenever I try to pass data that contains JSON, I get a wierd Javascript error that comes from Flash :

missing ) after argument list
try { __flash__toXML(Flash.Utilities.A..."")) ; } catch (e) { "<undefined/>"; }

It's impossible to get more information since this come from Flash and it's not bound to any Javascript file.

To reproduce this problem you can use this script :

package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.external.ExternalInterface;

    public class Main extends Sprite 
    {

        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            var test:String;

            test = "\"\\\"\"";

            ExternalInterface.call("console.log", test);
        }

    }

}

What can I do to avoid this problem and is it a known problem ?

2

There are 2 answers

1
HoLyVieR On BEST ANSWER

This is apparently a known issue and it doesn't seems like Adobe is going to fix it anytime soon.

I found a detailled explaination of this problem and basicly the issue seems to be that Flash doesn't handle the \ and the & properly which can lead to javascript error or data corruption during the transfer from Flash to javascript.

What Flash attempts to do when you transfer data from Flash to JS is to execute the following thing :

try {
    __flash__toXML(yourJavascriptFunction("[DATA]")) ;
} catch (e) { "<undefined/>"; }

The problem is that it puts your data raw and it doesn't escape the backslash at all. If your string contains only \ and you want to call console.log on it, it will try to do the following thing :

try {
    __flash__toXML(console.log("\")) ;
} catch (e) { "<undefined/>"; }

As you can see this is invalid javascript. It will throws an error in your Javascript console and it will never call console.log.

The solution is to either ducktape Flash behavior or do some nasty hack to get around it.

To ducktape Flash buggyness you can escape the blackslash before you transfer them. This solution will work for now, but when Flash will fix it (most probably not in a near future, if you consider that this bug is known for more than 4 years), it will break your application.

The other possibility is to url encode the character that Flash doesn't handle well (\, ", &) and to decode them on the other side.

Flash :

data = data.split("%").join("%25")
           .split("\\").join("%5c")
           .split("\"").join("%22")
           .split("&").join("%26");

Javascript :

data = data.replace(/%22/g, "\"")
           .replace(/%5c/g, "\\")
           .replace(/%26/g, "&")
           .replace(/%25/g, "%");

It's ugly, but it works.

0
indextwo On

Admittedly this wouldn't work directly for output to the console in Firebug, but for most other applications (i.e. sending a potentially 'invalid' string to Javascript), escape and unescape should work just fine:

AS3:

var testString:String = "\"\\\"\"";
ExternalInterface.call("showString", escape(testString));

And then in Javascript:

function showString(msg) {
    console.log(unescape(msg));
    document.getElementById('messagebox').innerHTML = unescape(msg);
}

<div id="messagebox"></div>