Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call dynamically created flash external interface in IE from javascript?

What I have:

  1. A swf exports a function via ExternalInterface
  2. Javascript creates new embed object and adds it to the document
  3. Calling flash functions works fine in other browsers
  4. Calling flash functions will fail in IE 8

Example of exporting functions in swf:

flash.external.ExternalInterface.addCallback("isActive", ...

Example of creating the embed object:

var b = document.createElement('embed');

    b.type = 'application\u002fx-shockwave-flash';
    b.setAttribute('allowFullScreen', 'true');
    b.setAttribute('allowNetworking', 'all');
    b.setAttribute('allowScriptAccess', 'always');
    b.width = 500;
    b.height = 400;
    b.src = 'assets\u002fUltra4.UltraApplication\u002fUltra4.UltraApplication+UltraSprite.swf';

Example of calling flash external interface in javascript:

   try
    {
      e = b.isActive();
    }
    catch (__exc){ }

In IE it will catch with message "Object doesn't support this property or method"

How to fix it?

  1. Related: http://bojolais.livejournal.com/251383.html
  2. Related: ExternalInterface not working in IE
  3. Related: http://swfupload.org/forum/generaldiscussion/985
  4. Related: http://code.google.com/p/doctype/wiki/ArticleFixingFlashExternalInterface
  5. Related: http://www.dangerouslyawesome.com/2006/10/20/another-swfobject-problem-deproblemed/
  6. Related: http://www.airtightinteractive.com/news/?p=71

In script debugger I can see a third party script which is supposed to be the bridge:

function __flash__arrayToXML(obj) {
    var s = "<array>";
    for (var i=0; i<obj.length; i++) {
        s += "<property id=\"" + i + "\">" + __flash__toXML(obj[i]) + "</property>";
    }
    return s+"</array>";
}
function __flash__argumentsToXML(obj,index) {
    var s = "<arguments>";
    for (var i=index; i<obj.length; i++) {
        s += __flash__toXML(obj[i]);
    }
    return s+"</arguments>";
}
function __flash__objectToXML(obj) {
    var s = "<object>";
    for (var prop in obj) {
        s += "<property id=\"" + prop + "\">" + __flash__toXML(obj[prop]) + "</property>";
    }
    return s+"</object>";
}
function __flash__escapeXML(s) {
    return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
}
function __flash__toXML(value) {
   var type = typeof(value);
    if (type == "string") {
        return "<string>" + __flash__escapeXML(value) + "</string>";
    } else if (type == "undefined") {
        return "<undefined/>";
    } else if (type == "number") {
        return "<number>" + value + "</number>";
    } else if (value == null) {
        return "<null/>";
    } else if (type == "boolean") {
        return value ? "<true/>" : "<false/>";
    } else if (value instanceof Date) {
        return "<date>" + value.getTime() + "</date>";
   } else if (value instanceof Array) {
       return __flash__arrayToXML(value);
   } else if (type == "object") {
       return __flash__objectToXML(value);
   } else {
        return "<null/>"; //???
    }
}
function __flash__addCallback(instance, name) {
  instance[name] = function () { 
    return eval(instance.CallFunction("<invoke name=\""+name+"\" returntype=\"javascript\">" + __flash__argumentsToXML(arguments,0) + "</invoke>"));
  }
}
function __flash__removeCallback(instance, name) {
  instance[name] = null;
}
like image 603
zproxy Avatar asked Jan 28 '10 13:01

zproxy


2 Answers

I'm not sure if I understand your question correctly. But I think you are missing a couple of things:

1) Your embed tag needs a name attribute. Let's name it "NewFlashMovie" for the subsequent code:

b.name = "NewFlashMovie";

2) You need to call the "isActive" function differently using an external function. First add this function

 function thisMovie(movieName) {
     if (navigator.appName.indexOf("Microsoft") != -1) {
         return window[movieName];
     } else {
         return document[movieName];
     }
 }

Then you can call the function like this

thisMovie("NewFlashMovie").isActive();

From my experience, this "thisMovie" is essential to bridge the IE-Flash calls. This is also documented in the ExternalInterface documentation

3) I also recommend using swfobject instead of creating your own "embed" object.

Hope these helps.

like image 193
jonycheung Avatar answered Oct 17 '22 06:10

jonycheung


I've found that, for IE, calling Javascript from ActionScript, I've needed to supply an "id" attribute to the object tag. The IE way of handling ExternalInterface.call(...) is to call a method on the object. IE issues the code

document.getElementById("...").SetReturnValue(...)

Without an id attribute on your object tag, this reduces to

document.getElementById("").SetReturnValue(...)

which tries to call SetReturnValue on a null object.

Note that the "id" attribute isn't required for other browsers but doesn't really hurt either.

Something similar may be happening in your case: Perhaps a "name" attribute on the embed may help.

like image 23
Mark Judd Avatar answered Oct 17 '22 06:10

Mark Judd