在 Google Chrome 中访问 ExternalInterface 公开方法时出现问题
Posted
技术标签:
【中文标题】在 Google Chrome 中访问 ExternalInterface 公开方法时出现问题【英文标题】:Problem accessing ExternalInterface exposed method in Google Chrome 【发布时间】:2010-11-29 00:48:10 【问题描述】:我的简单动作脚本 我正在尝试使用 Flash 的 ExternalInterface 设置回调,以便 javascript 可以调用我的 Flash 对象上的方法。在 Safari、Firefox 和 IE 中一切正常,但我无法让 Chrome 正常工作。当我在 Chrome 上尝试代码时,出现以下错误:
未捕获的类型错误:对象# 没有方法 'setText'
这是我正在使用的示例 html(同样,在 Safari、FF 和 IE 中都可以正常工作)
<html><body>
<div id="mycontent"></div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF("http://invincible.dynalias.com:8080/HelloWorld.swf", "mycontent", "400", "420", "9.0.0","expressInstall.swf", , allowScriptAccess:'always',id:'hw',name:'hw');
function getFlash(movieName)
return ( navigator.appName.indexOf("Microsoft") != -1) ? window[movieName] : document.getElementById(movieName);
</script><p>
<input type="text" id="exampleText" /> <input type="button" value="Set Text" onclick="getFlash('hw').setText(document.getElementById('exampleText')
.value)" />
</body>
</html>
这里是 ActionScript...
package
import flash.display.Sprite;
import flash.text.TextField;
import flash.external.ExternalInterface;
import flash.system.Security;
public class HelloWorld extends Sprite
private var textField:TextField = new TextField();
public function HelloWorld()
Security.allowDomain("*");
ExternalInterface.addCallback("setText", this.setText);
textField.text = "Hello, world!";
addChild(textField);
public function setText(text:String):void
this.textField.text = text;
【问题讨论】:
与你的问题无关,但你真的应该删除那个讨厌的navigator
sniff。
实际上,我 Mac 上的 Chrome 并没有抛出任何错误(并且似乎正确设置了文本)
你说得对,它在我的 Mac 上的 Chromium 上也同样适用于我。只是不是 Windows 上的 Chrome
我知道已经有一段时间了,但我在 Windows 上的 Chrome 中仍然遇到同样的问题,我偶然发现了这篇文章。你有没有为此想出解决方案?
不,没有人想出解决方案。
【参考方案1】:
我同意 Robson 的观点,即这是一种竞争条件,但它不是在“编写 Flash 标记”中,并且添加计时器不是一个好的解决方案 - 事实上它非常危险。
问题在于 SWF 本身没有加载并且有机会初始化您的外部接口。对于 Chrome 中的小型 SWF,时间可能比其他浏览器更敏感,但根本问题并非特定于 Chrome。
你需要做的是:
在动作脚本中
从你的构造函数调用这个函数:
public function InitializeExternalInterface():void
if (ExternalInterface.available)
// register actionscript functions so they can be called by JS
ExternalInterface.addCallback("activate", activate);
Security.allowDomain("www.example.com");
// send message to parent page that SWF is loaded and interface active
trace("External Interface Initialized...");
ExternalInterface.call("flashInitialized")
else
trace("ERROR: External Interface COULD NOT BE Initialized...");
在您的 HTML 中
<script>
function flashInitialized()
alert("Initialized!"); // remove this obviously!
$('#Main')[0].activate(); // safe to call Flash now
</script>
您可能会在本地计算机上发现没有此功能也可以正常工作,但是一旦您将网络延迟添加到等式中,您就会后悔没有这样做。任意计时器是一个坏主意,因为您仍然会在连接缓慢时收到错误。此方法让页面尽可能早地调用 flash 对象。
注意:使用 jQuery 的 'on ready' 模式并不是解决问题的方法 - 尽管一开始我把它误认为是一个。
$(function()
$('#animation')[0].SetTitle("Hello");
另外 swfobject 的 callbackFn
也不是一个解决方案,因为它只会告诉您何时插入标签,而不是何时加载 SWF。
【讨论】:
感谢您的解决方案,即使经过这么长时间。过了一会儿,我意识到这不是 Chrome 特定的问题,而是像你提到的那样试图加快回调。也感谢您的解决方案。 嗨西蒙,$('#Main')[0].activate();
是什么意思? #Main
在哪里?
activate() 只是flash影片中用ExternalInterface暴露的函数名(这里有一个函数activate()这里没有显示),Main是swf的ID为由 swfobject 创建
如果通过 ready 函数正确设置,定时器可能是一个更好的解决方案。例如,如果由于某种原因 Flash 在 JavaScript 函数之前被实例化,那么您的 flashInitialized 调用将失败。我所做的是在双方都有一个计时器,定期检查对方是否准备好,因为双方可能都有耗时的初始化例程。一旦双方都准备好了(即 Flash 知道 JavaScript 知道 Flash 已准备好),则允许通信。
我正在使用 Flash/JavaScript 桥接器,因此 Flash 可以使用 WebSockets 的浏览器实现。 JavaScript 必须先初始化一个套接字连接管理器类,Flash 才能使用它。所以通过实例化 JS 管理器类,然后在 document ready 中分配一个计时器来检查是否添加了 flash 的外部接口方法回调,它实际上可以通知 flash 它已准备好并且它知道 Flash 已准备好。 Flash 可以继续进行而不会出现问题。【参考方案2】:
我遇到了同样的问题,在 javascript 和 flash 之间触发和接收侦听器事件。
解决方案是使用来自 Adobe 的 AC_OETags.js 文件作为嵌入脚本而不是 JQuery flash。 (在Client Side detection下的zip文件中找到,Adobe可能在其他地方也有)
flash 在浏览器中构建 javascript 回调时基于竞争条件的问题。由于某种原因,直接嵌入无法正确处理此问题。
<div>
<script>
// Major version of Flash required
var requiredMajorVersion = 10;
// Minor version of Flash required
var requiredMinorVersion = 0;
var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision);
AC_FL_RunContent(
"src", "tagflash",
"width", "200",
"height", "200",
"id", "myTagFlash",
"quality", "high",
"bgcolor", "#FFFFFF",
"name", "myTagFlash",
"allowScriptAccess","always",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer",
"flashvars", "templateData=theYear:2010&theTagNumber:123"
);
</script>
</div>
然后你可以这样做:(适用于 IE、FF、Safari、Crome、++)
$("#tagFlash").gotoNewFrame();
【讨论】:
对不起,您能详细说明一下吗?你给它一个 src="tagflash",然后是 "myTagFlash" 的 id 和名称,但最后你最终通过 "tagFlash" 的 id(大写 F)调用它。你的意思是输入$("#myTagFlash").gotoNewFrame();
,对吧?
"allowScriptAccess","always" NOT "allowScriptAccess","allways"【参考方案3】:
我在使用 ExternalInterface 以及 Firefox 和 Chrome 时遇到问题,发现 Adobe Script 写入 Flash 标签的速度不够快,因此当浏览器试图找到 addCallback() 函数时,它当时不存在。
只需将调用 Flash 创建的 addCallback() 的 Javascript 函数放在 window.setTimeout() 调用中即可解决问题。小于 200 毫秒的延迟仍然会导致问题发生。
我不必使用尝试查找“length”属性是否存在于 document[FlashId] 对象中的解决方案。只需调用“FlashEmbed = document[FlashId]”就可以了。
【讨论】:
有意思,我一定要试试 对不起@Robson - 但这不是一个好主意。争用条件是由于未加载和运行 SWF 对象,而不是未写入标记本身。在慢速连接上下载 SWF 可能需要 10 秒,而且您可能永远不会在本地计算机上看到问题,因为您不会遇到这种网络延迟。请参阅我的回答,了解尽早调用 Flash 的最佳方式(我发现)。 我认为我们应该在 Flash 中放置一个重复计时器来检查 JavaScript 是否准备就绪。【参考方案4】:苦苦挣扎后,我终于决定使用Adobe官方的解决方案:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html
搜索ExternalInterfaceExample.as
。
【讨论】:
【参考方案5】:通过禁用 Chrome 内置 flash 插件可以解决该问题:
-
在chrome的地址栏中输入chrome://plugins。
点击右上角的详情展开插件详情。
在“Adobe Flash Player”的条目中,禁用第一个。
这不是解决方案,但说明了为什么在 Chrome 上会发生这种情况。 Chrome自带了一个flash插件,在我们使用AS3的ExternalInterface时经常会遇到麻烦,很烦。
【讨论】:
有时,内置插件可以工作。但是 Chrome 升级到新版本(如 28 版)后,内置插件中断了 ExternalInterface 调用以上是关于在 Google Chrome 中访问 ExternalInterface 公开方法时出现问题的主要内容,如果未能解决你的问题,请参考以下文章
无法在 Google Chrome 中访问外部 CSS 样式
在 Google Chrome 中访问 ExternalInterface 公开方法时出现问题
从 GOOGLE CHROME 访问网站时,访问者的信息未存储在数据库中