Функции, зарегистрированные в ExternalInterface.addCallback, недоступны в Javascript

Я работаю над Flash-игрой, которая должна вызвать Javascript на странице и получить от нее данные. Вызов Javascript из Flash работает. Вызов функций Flash из Javascript (часто) этого не делает.

Я использую Gaia Framework.

Что просходит:

  1. SWF загружен с SWFObject
  2. В файле Flash есть кнопка. По клику, он использует ExternalInterface.call() вызвать функцию Javascript. Это работает.
  3. Функция Javascript вызывает функцию Flash, которая была ExternalInterface.addCallback(),
  4. Иногда Javascript выдает следующую ошибку: TypeError: myFlash.testCallback is not a function,
  5. Когда происходит ошибка, это влияет на все функции, зарегистрированные с addCallback(), Gaia и некоторые из включенных в нее библиотек используют addCallback()и вызов этих функций из Javascript также вызывает ошибку TypeError.
  6. Долгое время ожидания нажатия кнопки во Flash не устраняет ошибку.
  7. После повторной попытки Flash addCallback() периодически не решает ошибку
  8. Когда возникает ошибка, ExternalInterface.available = true а также ExternalInterface.objectID содержит правильное имя для объекта встраивания Flash.
  9. Когда возникает ошибка, document.getElementById('myflashcontent') правильно возвращает объект Flash для встраивания.

Отредактировано, чтобы добавить:

  • Эта проблема обнаруживается в Firefox 3.6, но не в Chrome или IE8. Я не пробовал старые браузеры.
  • Я использую отладочную версию проигрывателя Flash.
  • Мои звонки ExternalInterface.addCallback() завернуты в try...catch блок. Когда происходит ошибка JS, catch блок не срабатывает. Это тихая ошибка.
  • Ошибка возникает при тестировании на веб-хосте, когда SWF-файл загружается с того же сервера, что и страница, на которой он находится.
  • Я поставил allowScriptAccess = always,
  • настройка flash.system.Security.allowDomain("mydomain") не исправляет ошибку

Из моего класса Page:

public class MyPage extends AbstractPage
{
    // declarations of stage instances and class variables

    // other functions

    override public function transitionIn():void 
    {
        send_button.addEventListener(MouseEvent.MOUSE_UP, callJS);
        exposeCallbacks();

        super.transitionIn();
    }

    private function exposeCallbacks():void
    {
        trace("exposeCallbacks()");
        if (ExternalInterface.available) {
            trace("ExternalInterface.objectID: " + ExternalInterface.objectID);
            try {
                ExternalInterface.addCallback("testCallback", simpleTestCallback);
                trace("called ExternalInterface.addCallback");
            }
            catch (error:SecurityError) {
                trace("A SecurityError occurred: " + error.message + "\n");
            }
            catch (error:Error) {
                trace("An Error occurred: " + error.message + "\n");
            }
        }
        else {
            trace("exposeCallbacks() - ExternalInterface not available");
        }
    }

    private function simpleTestCallback(str:String):void
    {
        trace("simpleTestCallback(str=\"" + str + "\")");
    }

    private function callJS(e:Event):void
    {
        if (ExternalInterface.available) {
            ExternalInterface.call("sendTest", "name", "url");
        }
        else {
            trace("callJS() - ExternalInterface not available");
        }
    }

}

Мой Javascript:

function sendTest(text, url) {
    var myFlash = document.getElementById("myflashcontent");

    var callbackStatus = "";
    callbackStatus += '\nmyFlash[testCallback]: ' + myFlash['testCallback'];
    //console.log(callbackStatus);

    var errors = false;
    try {
        myFlash.testCallback("test string");
    }
    catch (err) {
        alert("Error: " + err.toString());
        error = true;
    }

    if (!error) {
        alert("Success");
    }
}

var params = {
    quality: "high",
    scale: "noscale",
    wmode: "transparent",
    allowscriptaccess: "always",
    bgcolor: "#000000"
};
var flashVars = {
    siteXML: "xml/site.xml"
};
var attributes = {
    id: "myflashcontent",
    name: "myflashcontent"
};

// load the flash movie.
swfobject.embedSWF("http://myurl.com/main.swf?v2", "myflashcontent",
"728", "676", "10.0.0", serverRoot + "expressInstall.swf",
flashVars, params, attributes, function(returnObj) {
    console.log('Returned ' + returnObj.success);
    if (returnObj.success) { returnObj.ref.focus(); }
});

8 ответов

Звонки в JS через ExternalInterface заключены в try { } блок, и это приводит к подавлению последующих ошибок JS.

Обходной путь для того же - вызвать закрытие функции в JavaScript и выполнить реальный код после истечения времени ожидания.

Пример:

function myFnCalledByEI (arg1, arg2) {

    setTimeout(myActualFunction () {
       // You can use arg1 and arg2 here as well!
       // Errors raised within this function will not be
       // suppressed.
    }, 0);

};

Это может быть похоже на проблему, с которой вы столкнулись.

http://www.google.com/support/forum/p/translator-toolkit-api/thread?tid=58cda1b34ae1e944&hl=en

Вот наш сценарий, когда мы сузили все условия:

  • Только на FireFox/Windows
  • Только когда wmode= прозрачный
  • Только при использовании функции js alert()

В этом конкретном сценарии ExternalInterface.call() не сработает сразу. Это сработало только после небольшой задержки с классом Timer.

Если мы сделали wmode=window или удалили alert() - все заработало. Попробуйте использовать console.log() для отображения отладочного текста в firebug.

Другой гоча? Возвращает ли ваша функция js массив или объект против строки. Удивительно, но возвращенный нативный массив js был интерпретирован массивом во Flash. Попробуйте вывести информацию о ваших возвращаемых данных следующим образом:

var myRetVal = flash.external.ExternalInterface.call("my_js_func");
debug_txt.text = flash.utils.describeType(myRetVal).toString();

Мы столкнулись с той же проблемой, и только в Firefox.

Следуя совету THM, мы смогли найти решение.

В нашем случае вставляемый SWF-файл находился внутри div, анимированного в виде с помощью jQuery.slideDown (). Это, по-видимому, иногда приводит к перезагрузке при запуске. В некоторых случаях это приводило к недоступности функций обратного вызова.

Исправлено вызовом swfobject.embedSWF только после завершения эффекта slideDown.

Я получал эту ошибку, потому что у меня был один и тот же файл Flash на странице несколько раз. Хотя у каждого из них был свой идентификатор / имя, все они использовали один и тот же обратный вызов.

Вы пробовали это в JavaScript?

if (myFlash)    
{
  if (!myFlash.testCallback)
  {
    if (__flash__addCallback)
    { 
       __flash__addCallback( myFlash, "testCallback" );
    }
    else
    {
      console.log("Error: Flash External Interface injected JavaScript function not found. The external interface function won't work.");
    }
  }
}

myFlash.testCallback("test string");  

Я использовал это во многих случаях.

Снова в определенных местах мне пришлось переопределить функции __flash_addCallback и _flash_removeCallback, чтобы минимизировать ошибки.

В настоящее время я не помню, что я сделал для __flash_addCallback, но вот что я сделал для последнего:

if (__flash__removeCallback) 
{
   __flash__removeCallback = function (instance, name) {if(instance && instance[name]) instance[name] = null;
}

Я попробовал ваш код, и он работал нормально, если я поставил предупреждение перед всем, поэтому я думаю, что это что-то, связанное с тем, что вам нужно подождать.

Вы можете увидеть этот тип сообщения об ошибке, если во Flash произошла ошибка. Что-то вроде необъяснимого исключения.

Вы используете отладочную версию плеера? Это может дать вам больше информации о том, что происходит.

Кроме того, это согласуется во всех браузерах? Я видел старые версии IE, у которых были проблемы с принятием нескольких последовательных вызовов Flash <-> JS.

J

Другие вопросы по тегам