外部接口和 Internet Explorer 9 问题
天哪,我讨厌外部接口吗?我有一个视频播放器,它利用外部接口来控制 Flash 对象并允许 Flash 对象将消息传递给相同的 JavaScript。有一段时间它在所有浏览器中都运行良好。然后几天前,在我将项目移出开发之前,我去所有浏览器中测试它,发现该应用程序在 Internet Explorer 9 中损坏。控制台中出现以下错误:
SCRIPT16389: Could not complete the operation due to error 8070000c.
jquery.min.js, line 16 character 29366
My javascript file is very long but here是重要的部分。我的所有操作都包含在我创建的对象中。在我的一个方法中,我有以下几行:
var that = this;
that.stop();
这是该方法调用的所有方法:
this.stop = function(){
var that = this;
console.log('stop called');
that.pause();
that.seek(0);
that.isPlaying = false;
console.log('stop finished');
};
this.pause = function(){
var that = this;
console.log('pause called');
if(that.player == 'undefined' || that.player == null){
that.player = that.GetMediaObject(that.playerID);
}
that.player.pauseMedia(); //external interface call
that.isPlaying = false;
console.log('pause finished');
};
this.seek = function(seek){
var that = this;
console.log('seek called');
if(that.player == 'undefined' || that.player ==null){
console.log("player="+that.player+". resetting player object");
that.player = that.GetMediaObject(that.playerID);
console.log("player="+that.player);
}
that.player.scrubMedia(seek); //external interface call
console.log('seek finished');
};
//this method returns a reference to my player. This method is call once when the page loads and then again as necessary by all methods that make external interface calls
this.GetMediaObject = function(playerID){
var mediaObj = swfobject.getObjectById(playerID);
console.log('fetching media object: ' +mediaObj );
//if swfobject.getObjectById fails
if(typeof mediaObj == 'undefined' || mediaObj == null){
console.log('secondary fetch required');
var isIE = navigator.userAgent.match(/MSIE/i);
mediaObj = isIE ? window[playerID] : document[playerID];
}
return mediaObj;
};
这是我的 console.log 语句的输出:
LOG: fetching media object: [object HTMLObjectElement]
LOG: video-obj-1: ready
LOG: stop called
LOG: pause called
LOG: pause finished
LOG: seek called
LOG: player=[object HTMLObjectElement]
SCRIPT16389: Could not complete the operation due to error 8070000c.
jquery.min.js, line 16 character 29366
有趣的是,似乎第一个外部接口调用 ' that.player.pauseMedia()' 没有任何问题,但后续调用 'that.player.scrubMedia(0)' 失败。另一个奇怪的事情是它指出 jquery 作为错误的来源,但在这些函数中没有调用 jquery。
这就是我所知道的。这不是我的时机不对的问题。当 Flash 对象完全加载时,我的动作脚本的最后一行向 JavaScript 发送一条消息。另外,我将参数“allowScriptAccess”设置为“始终”,所以也不是这样。我们使用的动作脚本文件已在以前的项目中使用过,所以我 90% 确定这不是问题。
无论如何,这是我的动作脚本。我没有编写动作脚本,而且我对该语言不太熟悉,但我尝试放入与我的应用程序最相关的部分:
flash.system.Security.allowDomain("*.mydomain.com");
import flash.external.ExternalInterface;
// variables to store local information about the current media
var mediaEmbedServer:String = "www";
var mediaPlayerID:String;
var mediaFile:String;
var mediaDuration:Number;
// variables to be watched by actionscript and message javascript on changes
var mediaPositions:String = "0,0"; // buffer position, scrub position
var mediaStatus:String;
var netStreamClient:Object = new Object();
netStreamClient.onMetaData = metaDataHandler;
netStreamClient.onCuePoint = cuePointHandler;
var connection:NetConnection;
var stream:NetStream;
var media:Video = new Video();
// grab the media's duration when it becomes available
function metaDataHandler(info:Object):void {
mediaDuration = info.duration;
}
function cuePointHandler(info:Object):void {
}
connection = new NetConnection();
connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
try {
var paramName:String;
var paramValue:String;
var paramObject:Object = LoaderInfo(this.root.loaderInfo).parameters;
for (paramName in paramObject) {
paramValue = String(paramObject[paramName]);
switch (paramName){
case "server":
mediaEmbedServer = paramValue;
break
case "playerID":
mediaPlayerID = paramValue;
break
}
}
} catch (error:Error) {
}
if (mediaEmbedServer == "dev" || mediaEmbedServer == "dev2"){
connection.connect("rtmp://media.developmentMediaServer.com/myApp");
} else {
connection.connect("rtmp://media.myMediaServer.com/myApp");
}
function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
}
function connectStream():void {
stream = new NetStream(connection);
stream.soundTransform = new SoundTransform(1);
stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
stream.client = netStreamClient;
media.attachNetStream(stream);
media.width = 720;
media.height = 405;
addChild(media);
}
function netStatusHandler(stats:NetStatusEvent){
switch (stats.info.code){
case "NetConnection.Connect.Success":
connectStream();
break;
case "NetConnection.Call.BadVersion":
case "NetConnection.Call.Failed":
case "NetConnection.Call.Prohibited":
case "NetConnection.Connect.AppShutdown":
case "NetConnection.Connect.Failed":
case "NetConnection.Connect.InvalidApp":
case "NetConnection.Connect.Rejected":
case "NetGroup.Connect.Failed":
case "NetGroup.Connect.Rejected":
case "NetStream.Connect.Failed":
case "NetStream.Connect.Rejected":
case "NetStream.Failed":
case "NetStream.Play.Failed":
case "NetStream.Play.FileStructureInvalid":
case "NetStream.Play.NoSupportedTrackFound":
case "NetStream.Play.StreamNotFound":
case "NetStream.Seek.Failed":
case "NetStream.Seek.InvalidTime":
// report error status and reset javascriptPlay
clearInterval(progressInterval);
messageStatus("error");
break;
default:
// check time through file to determine if media is over
if (stream.time > 0 && stream.time >= (mediaDuration - .25)){
// reset media if it has ended
clearInterval(progressInterval);
stream.play(mediaFile, 0, 0);
messageStatus("finished");
}
}
};
var progressInterval:Number;
// respond to a play/pause request by playing/pausing the current stream
function pauseMedia(){
clearInterval(progressInterval);
if (mediaStatus == 'playing'){
stream.pause();
messageStatus("paused");
}
};
ExternalInterface.addCallback( "pauseMedia", pauseMedia );
// respond to a scrub request by seeking to a position in the media
function scrubMedia(newPosition){
clearInterval(progressInterval);
if (mediaStatus == "playing"){
stream.pause();
messageStatus("paused");
}
stream.seek(newPosition * mediaDuration);
var positionSeconds = newPosition * mediaDuration;
messagePositions(positionSeconds+","+positionSeconds);
};
ExternalInterface.addCallback( "scrubMedia", scrubMedia );
ExternalInterface.call("MediaPlayerReady", mediaPlayerID);
Boy-oh-boy do I hate external interface. I have a video player that utilizes external interface to control the flash object and to allow the flash object to pass messages to the same javascript. For a time it worked well in all browsers. Then a few days ago i went to go test it in all browsers before i moved the project out of development, and found that the application broke in internet explorer 9. The following error appeared in the console:
SCRIPT16389: Could not complete the operation due to error 8070000c.
jquery.min.js, line 16 character 29366
My javascript file is really long but here are the important parts. All my actions are contained in an object that i created. Inside one of my methods i have the following lines:
var that = this;
that.stop();
here are all the methods that get called as a result of that method:
this.stop = function(){
var that = this;
console.log('stop called');
that.pause();
that.seek(0);
that.isPlaying = false;
console.log('stop finished');
};
this.pause = function(){
var that = this;
console.log('pause called');
if(that.player == 'undefined' || that.player == null){
that.player = that.GetMediaObject(that.playerID);
}
that.player.pauseMedia(); //external interface call
that.isPlaying = false;
console.log('pause finished');
};
this.seek = function(seek){
var that = this;
console.log('seek called');
if(that.player == 'undefined' || that.player ==null){
console.log("player="+that.player+". resetting player object");
that.player = that.GetMediaObject(that.playerID);
console.log("player="+that.player);
}
that.player.scrubMedia(seek); //external interface call
console.log('seek finished');
};
//this method returns a reference to my player. This method is call once when the page loads and then again as necessary by all methods that make external interface calls
this.GetMediaObject = function(playerID){
var mediaObj = swfobject.getObjectById(playerID);
console.log('fetching media object: ' +mediaObj );
//if swfobject.getObjectById fails
if(typeof mediaObj == 'undefined' || mediaObj == null){
console.log('secondary fetch required');
var isIE = navigator.userAgent.match(/MSIE/i);
mediaObj = isIE ? window[playerID] : document[playerID];
}
return mediaObj;
};
Here's the output from my console.log statments:
LOG: fetching media object: [object HTMLObjectElement]
LOG: video-obj-1: ready
LOG: stop called
LOG: pause called
LOG: pause finished
LOG: seek called
LOG: player=[object HTMLObjectElement]
SCRIPT16389: Could not complete the operation due to error 8070000c.
jquery.min.js, line 16 character 29366
The interesting thing is that it appears that the first external interface call 'that.player.pauseMedia()' doesn't have any issue, but the subsequent call to 'that.player.scrubMedia(0)' fails. Another odd thing is that it points to jquery as the source of the error, but there's no call to jquery in those functions.
Here's what i know it's not. It is not an issue where my timing is off. The last line of my actionscript sends a message to the javascript when the flash object has completely loaded. Also i set the parameter 'allowScriptAccess' to 'always' so it's not that either. The actionscript file we use has been used in previous projects so i am 90% certain that that is not the issue.
here's my actionscript anyways. I didn't write actionscript and i'm not too familiar with the language but I tried to put in the parts that seemed most pertinent to my application:
flash.system.Security.allowDomain("*.mydomain.com");
import flash.external.ExternalInterface;
// variables to store local information about the current media
var mediaEmbedServer:String = "www";
var mediaPlayerID:String;
var mediaFile:String;
var mediaDuration:Number;
// variables to be watched by actionscript and message javascript on changes
var mediaPositions:String = "0,0"; // buffer position, scrub position
var mediaStatus:String;
var netStreamClient:Object = new Object();
netStreamClient.onMetaData = metaDataHandler;
netStreamClient.onCuePoint = cuePointHandler;
var connection:NetConnection;
var stream:NetStream;
var media:Video = new Video();
// grab the media's duration when it becomes available
function metaDataHandler(info:Object):void {
mediaDuration = info.duration;
}
function cuePointHandler(info:Object):void {
}
connection = new NetConnection();
connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
try {
var paramName:String;
var paramValue:String;
var paramObject:Object = LoaderInfo(this.root.loaderInfo).parameters;
for (paramName in paramObject) {
paramValue = String(paramObject[paramName]);
switch (paramName){
case "server":
mediaEmbedServer = paramValue;
break
case "playerID":
mediaPlayerID = paramValue;
break
}
}
} catch (error:Error) {
}
if (mediaEmbedServer == "dev" || mediaEmbedServer == "dev2"){
connection.connect("rtmp://media.developmentMediaServer.com/myApp");
} else {
connection.connect("rtmp://media.myMediaServer.com/myApp");
}
function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
}
function connectStream():void {
stream = new NetStream(connection);
stream.soundTransform = new SoundTransform(1);
stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
stream.client = netStreamClient;
media.attachNetStream(stream);
media.width = 720;
media.height = 405;
addChild(media);
}
function netStatusHandler(stats:NetStatusEvent){
switch (stats.info.code){
case "NetConnection.Connect.Success":
connectStream();
break;
case "NetConnection.Call.BadVersion":
case "NetConnection.Call.Failed":
case "NetConnection.Call.Prohibited":
case "NetConnection.Connect.AppShutdown":
case "NetConnection.Connect.Failed":
case "NetConnection.Connect.InvalidApp":
case "NetConnection.Connect.Rejected":
case "NetGroup.Connect.Failed":
case "NetGroup.Connect.Rejected":
case "NetStream.Connect.Failed":
case "NetStream.Connect.Rejected":
case "NetStream.Failed":
case "NetStream.Play.Failed":
case "NetStream.Play.FileStructureInvalid":
case "NetStream.Play.NoSupportedTrackFound":
case "NetStream.Play.StreamNotFound":
case "NetStream.Seek.Failed":
case "NetStream.Seek.InvalidTime":
// report error status and reset javascriptPlay
clearInterval(progressInterval);
messageStatus("error");
break;
default:
// check time through file to determine if media is over
if (stream.time > 0 && stream.time >= (mediaDuration - .25)){
// reset media if it has ended
clearInterval(progressInterval);
stream.play(mediaFile, 0, 0);
messageStatus("finished");
}
}
};
var progressInterval:Number;
// respond to a play/pause request by playing/pausing the current stream
function pauseMedia(){
clearInterval(progressInterval);
if (mediaStatus == 'playing'){
stream.pause();
messageStatus("paused");
}
};
ExternalInterface.addCallback( "pauseMedia", pauseMedia );
// respond to a scrub request by seeking to a position in the media
function scrubMedia(newPosition){
clearInterval(progressInterval);
if (mediaStatus == "playing"){
stream.pause();
messageStatus("paused");
}
stream.seek(newPosition * mediaDuration);
var positionSeconds = newPosition * mediaDuration;
messagePositions(positionSeconds+","+positionSeconds);
};
ExternalInterface.addCallback( "scrubMedia", scrubMedia );
ExternalInterface.call("MediaPlayerReady", mediaPlayerID);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
听起来像是未定义的expando属性,可能是由未定义的expando属性引起的="http://bugs.jquery.com/ticket/8485" rel="nofollow">jQuery IE9 错误。调试它的最好方法是删除 userAgent 测试,代之以对 object 元素的检查,例如:
查看 jQuery 第一次单击后 ID 属性是否正在更改。
Sounds like an undefined expando property which may be caused by a jQuery IE9 bug. The best way to debug it is to remove the userAgent test and replace it with a check for the object element, such as:
to see whether the ID attribute is being changed after the first click by jQuery.
我在使用 JPEGCam 时遇到了这个问题,它也使用 flash 的外部接口。我的网络摄像头控件在 div 中动态加载,然后会在 IE(不是 Firefox 或 chrome)中抛出此错误。将 Flash 控件的初始化移动到父页面中的 document.ready,然后根据需要隐藏/显示/移动控件后,我能够解决此异常。
希望有帮助。
I had this problem using JPEGCam, which also uses flash's external interface. My webcam control was being loaded dynamically within a div, and would then throw this error in IE (not firefox or chrome). After moving the initialization of my flash control to document.ready in the parent page, then hiding/showing/moving the control as needed, i was able to work around this exception.
Hope that helps.