Development Shack Technology Understood

ExternalInterface.call and ExternalInterface.addCallback not working in IE AND Chrome, Firefox, Safari  

For those looking for an example that actually works (like me for the last 2 hours).

Here is a list of requirements you must fulfill in order for ExternalInterface to work:

  • Make sure to use document[movieID] for NON-IE browsers
  • Make sure to use window[movieID] for IE browsers
  • Make sure the OBJECT tag has a PARAM tag for allowScriptAccess="sameDomain" or allowScriptAccess="always"
  • Make sure the EMBED tag has attribute for allowScriptAccess="sameDomain" or allowScriptAccess="always"
  • Make sure the EMBED tag has the NAME attribute set (do NOT set an ID attribute here because it is not required and may cause more problems for you)
  • Make sure the OBJECT tag has an ID attribute set (also, make sure it is NOT the same as the NAME attribute on the EMBED tag)

The following example is a client-side file reader. It allows us to access an XML file from the client-side without a round-trip to the server.

There is one special requirement for this particular solution to work:

The user must click on the Flash movie itself... the JavaScript can't tell the Flash to bring up the Open file dialog (Google Error #2176).

Here is the HTML/JavaScript:

<script type="text/javascript">

function callback(text) {
    console.log(text);
}

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

function debugFlash(t) {
    console.log("debugFlash: " + t);
}

function setupFlashUploader(o) {
    var component = thisMovie("ClientUploader");

    component.setCallbackMethod('callback');
    component.resetFilters();
    component.addFileFilter('Text Files', '*.txt');
}

</script>

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="ClientUploaderIE"
    codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,1,52,0"
    width="100" height="22">
        <param name="movie" value="client-uploader.swf" />
        <param name="bgcolor" value="#ffffff" />
        <param name="allowScriptAccess" value="always" />
        <embed src="client-uploader.swf" quality="high" bgcolor="#ffffff"
            width="100" height="22" align="middle" name="ClientUploader"
            play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
            type="application/x-shockwave-flash"
            pluginspage="http://www.macromedia.com/go/getflashplayer">
        </embed>
</object>

And here is the Flash ActionScript:

import flash.net.FileReference;
import flash.net.FileFilter;

var fileRef:FileReference = new FileReference();
var callback:String;
var selectFilters:Array = [ new FileFilter("All Files", "*.*") ];

fileRef.addEventListener(Event.COMPLETE, onFileLoaded);
fileRef.addEventListener(Event.SELECT, onFileSelected);

function setCallbackMethod(cb:String):void {
    callback = cb;
}

function resetFilters():void {
    selectFilters = new Array();
}

function addFileFilter(label:String, ext:String):void {
    selectFilters.push(new FileFilter(label, ext));
}

btnUpload.addEventListener(MouseEvent.CLICK, onUploadFile);

function onUploadFile(e:Event):void {
    ExternalInterface.call("setupFlashUploader", "");
    ExternalInterface.call("debugFlash", "Loading file...");
    try {
        if (fileRef.browse(selectFilters)) {
            ExternalInterface.call("debugFlash", "Selecting file...");
        } else {
            ExternalInterface.call("debugFlash", "NOT Selecting file...");
        }
    } catch (e:Error) {
        ExternalInterface.call("debugFlash", e.toString());
    }
}

function onFileLoaded(e:Event):void {
    var textContent:String = fileRef.data.toString();
    ExternalInterface.call(callback, textContent);
}

function onFileSelected(e:Event):void {
    fileRef.load();
}

ExternalInterface.addCallback('setCallbackMethod', setCallbackMethod);
ExternalInterface.addCallback('resetFilters', resetFilters);
ExternalInterface.addCallback('addFileFilter', addFileFilter);