ExternalInterface.addCallback注册的函数在浏览器中的兼容性问题
现在做一个小应用,要求使用js调用flash中的函数,就使用了ExternalInterface.addCallback函数。之前用过一次,按照官方API上的方法做了以后,发现只有IE是能正常调用的,其他浏览器都不行,但是上次只是试验阶段,就没有深究。这回就不行了,搞了两天还是有点问题。下面就慢慢说一说吧。
首先真的是除了IE都不能使用,报错是在其他浏览器中找不到那个flash(js获取的object为空),后来看了http://www.iamued.com/demo/flashjs/这篇文章后就明白了,重点在于object的id属性, EMBED的name属性及swliveconnect=”true”属性,然后还修改了js获取flash的方法。同时我还试验了这篇文章中提到的Play(),StopPlay()这些JS固有的控制flash的方法。这回以后,在IE和Opera中好用了。但是在FF、Chrome中除了Play(),StopPlay()这些方法是可用的,自己在flash中使用ExternalInterface.addCallback注册的方法却调用不成功,提示has no method 'flushTickets'(在flash中是这么写的ExternalInterface.addCallback("flushTickets",flushTicketsforjs);)。
后来有人说用swfobject.js来嵌入swf会比较好(使用方法http://www.cnblogs.com/lunalord/archive/2011/03/03/1967992.html),于是就试了一把,结果还是一样。
接着又看了这篇文章http://tech.cncms.com/tuxing/flash/93749.html,这里主要讲的是要注意安全沙箱问题和swf是否完全加载的问题。我就把allowScriptAccess的值由原来的sameDomain改为了always;在flash中添加Security.allowDomain("*")和Security.allowInsecureDomain("*");让flash监听全部加载完后出现ready字样。这样修改后在FF和windows版的Safari中居然神奇的OK的,但是Chrome中还是那副屎样。我开始怀疑是不是我电脑Chrome的问题(因为我的电脑的Chrome使用video标签的时候放MP4只有声音没有图像),然后就放到一个同事的电脑上去试了,结果他那的浏览器没有一个测试成功的,真是崩溃啊。本着自欺欺人的态度,我认为那是同事电脑的问题。
然后看了http://www.cuplayer.com/player/PlayerCodeAs/2012/0724310.html,这篇文章后我就try了一下,发在在Chrome中在注册函数的时候是出现了SecurityError#2060的错误,官方解释:2060安全沙箱冲突:ExternalInterface 调用者 %1无法访问 %2。我猜想可能是Chrome强制检验安全沙箱了,之前一直都是本地运行,所以在域上可能会有问题。那干脆就放到IIS中去试试。
结果……
结果……
结果真的可以了。猜想之前ff中的问题应该也是这个,只是域修改为通配符“*”后就好了。忙乎小一天,终于解决了!
下面放送代码
flash部分
testTxt是在舞台上的一个动态文本。
package
{
import flash.display.MovieClip;
import flash.external.ExternalInterface;
import flash.system.System;
import flash.system.Security;
import flash.events.Event;
public class MapMain extends MovieClip
{
public function MapMain()
{
testTxt.text=String(ExternalInterface.available);
Security.allowDomain("*");
Security.allowInsecureDomain("*");
this.loaderInfo.addEventListener(Event.COMPLETE,onthisswfready);
try
{
ExternalInterface.addCallback("flushTickets",flushTicketsforjs);
}
catch(e:SecurityError)
{
testTxt.appendText("_"+e.toString());
}
}
private function onthisswfready(evt:Event):void
{
this.loaderInfo.removeEventListener(Event.COMPLETE,onthisswfready);
testTxt.appendText("_ready");
}
private function flushTicketsforjs():void
{
//由js中触发主动的更新数据
testTxt.text="数据已经更新了";
}
}
}
html部分
</style>
<script type="text/javascript">
function onclickHandler()
{
thisMapMovie("mapff").flushTickets();
}
function onstopHandler()
{
thisMapMovie("mapff").StopPlay();
}
function onplayHandler()
{
thisMapMovie("mapff").Play();
}
function thisMapMovie(movieName)
{
if (window.document[movieName])
{
return window.document[movieName];
}
if (navigator.appName.indexOf("Microsoft Internet")==-1)
{
if (document.embeds &&document.embeds[movieName])
return document.embeds[movieName];
}
else // if (navigator.appName.indexOf("MicrosoftInternet")!=-1)
{
return document.getElementByIdx_x_x(movieName);
}
}
</script>
“<body>
<input type="button" value="刷新数据"onclick="onclickHandler();" />
<input type="button" value="停止"onclick="onstopHandler();" />
<input type="button" value="播放"onclick="onplayHandler();" />
<div id="flashContent">
<objectclassid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="550"height="400" id="mapff" align="middle">
<param name="movie" value="mapf.swf"/>
<param name="quality" value="high"/>
<param name="bgcolor" value="#ffffff"/>
<param name="play" value="true"/>
<param name="loop" value="true"/>
<param name="wmode" value="window"/>
<param name="scale" value="showall"/>
<param name="menu" value="true"/>
<param name="devicefont" value="false"/>
<param name="salign" value=""/>
<param name="allowScriptAccess" value="always"/>
<param name="swliveconnect"value="true"/>
<embed play="true" swliveconnect="true" name="mapff"src="mapf.swf" quality="high" bgcolor="#FFFFFF" width="550"height="400" type="application/x-shockwave-flash"swliveconnect="true"pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"/>
</object>
</div>
</body>”