Функции, зарегистрированные в ExternalInterface.addCallback, недоступны в Javascript
Я работаю над Flash-игрой, которая должна вызвать Javascript на странице и получить от нее данные. Вызов Javascript из Flash работает. Вызов функций Flash из Javascript (часто) этого не делает.
Я использую Gaia Framework.
Что просходит:
- SWF загружен с SWFObject
- В файле Flash есть кнопка. По клику, он использует
ExternalInterface.call()
вызвать функцию Javascript. Это работает. - Функция Javascript вызывает функцию Flash, которая была
ExternalInterface.addCallback()
, - Иногда Javascript выдает следующую ошибку:
TypeError: myFlash.testCallback is not a function
, - Когда происходит ошибка, это влияет на все функции, зарегистрированные с
addCallback()
, Gaia и некоторые из включенных в нее библиотек используютaddCallback()
и вызов этих функций из Javascript также вызывает ошибку TypeError. - Долгое время ожидания нажатия кнопки во Flash не устраняет ошибку.
- После повторной попытки Flash
addCallback()
периодически не решает ошибку - Когда возникает ошибка,
ExternalInterface.available = true
а такжеExternalInterface.objectID
содержит правильное имя для объекта встраивания Flash. - Когда возникает ошибка,
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