Почему ExternalInterface ломается, когда я передаю параметр с помощью строки JSON?

У меня очень странная проблема с Flash 10 и ExternalInterface. В настоящее время я использую самодельный мост для использования RTMFP с Javascript, и всякий раз, когда я пытаюсь передать данные, содержащие JSON, я получаю странную ошибку Javascript, которая исходит от Flash:

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

Невозможно получить больше информации, поскольку это происходит из Flash и не связано с каким-либо файлом Javascript.

Чтобы воспроизвести эту проблему, вы можете использовать этот 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);
        }

    }

}

Что я могу сделать, чтобы избежать этой проблемы и это известная проблема?

Ответы

Ответ 1

Это, по-видимому, известная проблема, и, похоже, Adobe не собирается исправлять ее в ближайшее время.

Я нашел подробное объяснение этой проблемы, и в основном проблема заключается в том, что Flash не обрабатывает \ и & правильно, что может приводят к ошибке javascript или повреждению данных во время перехода от Flash к javascript.

То, что Flash пытается выполнить при передаче данных из Flash в JS, заключается в следующем:

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

Проблема заключается в том, что он помещает ваши данные в исходное состояние, и он вообще не скрывает обратную косую черту. Если ваша строка содержит только \ и вы хотите называть ее console.log, она попытается сделать следующее:

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

Как вы видите, это недопустимый javascript. Это вызовет ошибку в вашей консоли Javascript, и она никогда не вызовет console.log.

Решением является либо поведение во флеш-режиме ducktape, либо некоторые неприятные хаки, чтобы обойти его.

В ducktape Flash buggyness вы можете избежать черной полосы, прежде чем переносить их. Это решение будет работать до сих пор, но когда Flash его исправит (скорее всего, не в ближайшем будущем, если вы считаете, что эта ошибка известна более 4 лет), она нарушит ваше приложение.

Другая возможность заключается в том, чтобы url кодировать символ, который Flash плохо обрабатывает (\, ", &) и декодировать их с другой стороны.

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, "%");

Это уродливо, но оно работает.

Ответ 2

По общему признанию, это не будет работать непосредственно для вывода на консоль в Firebug, но для большинства других приложений (т.е. отправки потенциально "недопустимой" строки в Javascript) escape и unescape должны работать нормально:

AS3:

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

И затем в Javascript:

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

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