A colleague (Brad) is trying to get his Flex application to talk to a PDF through the HTML wrapper and asked me if I knew how to set up communication between Flex and the browser. I don't know if it will help him much, but I wrote up an e-mail with what I knew and sent it along. Once I was done, I thought that it might just be of help to someone else out there so here is a beefed-up version of what I sent to him (with added home-made diagrams!)
(I apologize ahead of time if the source code formatting isn't ideal... I cut and pasted it from my original e-mail and Outlook really mangled it.)
Flex and Javascript Getting Chatty: The ExternalInterface Class
The ExternalInterface
class provides a few static methods that allow both Flex to invoke
Javascript functions and Javascript to invoke Flex functions. In usual
practice, when run on the web, a Flex SWF is embedded in an HTML
document (a.k.a. the HTML "Wrapper"). This document is like any other
HTML document, and can therefore include CSS information and
Javascript. Thanks to the Flex ExternalInterface class, the Javascript
inside the HTML wrapper is exposed to the SWF. The ExternalInterface
also allows the SWF to expose a public interface to the HTML wrapper's
Javascript code.

If you take a moment to think about the possibilities, you quickly realize that you can accomplish many powerful things using this functionality...
- Flex to AJAX communication
- Flex to Flex
communication (within a single HTML wrapper)
- Flex to Acrobat communication (as in Brad's case)
- Flex to anything else that exposes functionality to Javascript code in the HTML wrapper (i.e. other plug-ins)

In order to expose the functionality of your Flex app to outside forces, you need to register any outward-facing functions with the ExternalInterface by giving them an outward-facing name:
e.g.
if (ExternalInterface.available) {
// This makes
a function called "populateCookieContextValues" available to the browser.
ExternalInterface.addCallback("populateCookieContextValues",
function ():void {
// This function would do something.
}
);
ExternalInterface.addCallback("returnAllTasksToGroupQueueOnClose", myFunction);
private
function myFunction (parameter:String):void {
// This function would do something else.
}
} else {
trace("Houston,
we have a problem.");
}
Inside
your wrapper, you must give a name to the embedded SWF within the
<embed/> tags, and using that name (here we'll call it "main"),
you can get a handle on the SWF through Javascript. (If I'm not
mistaken, by deafult, that's the name used by FlexBuilder when it
generates the HTML wrapper for a new project.)
Note
that for IE and a Mozilla browser, the location of the SWF in the
document object model (DOM) is slightly different. In IE it can be
found in the window, in Firefox et al. it is in the document.
e.g.
function callPopulateCookieContextValues() {
// If we are using IE
if (navigator.appName.indexOf("Microsoft") != -1) {
window["main"].populateCookieContextValues;
// Otherwise we are using Firefox or equivalent
} else {
document["main"].populateCookieContextValues;
}
}
Calling functions in the HTML wrapper from Flex (Flex to
Javascript):
e.g.
if (ExternalInterface.available) {
try {
//
Invoke the get_cookie function, feeding it the "someParameter" String.
var
returnedString:String = ExternalInterface.call("get_cookie", "someParameter"));
} catch (e:Error) {
//
A problem occurred making the call
trace("Houston, we have a problem.");
}
} else {
// No external
interface available
trace("Houston,
we have a problem.");
}
Another (Cool) Way To Call Javascript
e.g.
if (ExternalInterface.available) {
// Close the
browser window
ExternalInterface.call("eval", "window.close();");
} else {
// No external
interface available
trace("Houston,
we have a problem.");
}
It is good practice to check if the ExternalInterface is available before making calls to it. Also, you'll want to put your calls into try/catch blocks, so that you can detect and gracefully handle failures. You must remember that when dealing with all of the different browsers out there, you never know when perfectly good Javascript is going to suddenly fail on you.
One Last Thing
Finally, it seems self-evident but I'll still mention that because the ExternalInterface is a bridge between your SWF and the HTML wrapper (and hence the browser), it follows that Air doesn't support the ExternalInterface class, since it doesn't run inside of a browser.
Hopefully this brief overview will help somebody out there make use of this powerful tool. The ExternalInterface opens up a door to so many possibilities that I haven't mentioned or even though of, so I invite you to post links to cool uses you've made of the ExternalInterface in your own projects.
Thank you!
ADDENDUM:
As kindly pointed out in a comment by John Dowdell of Adobe, technically there is no such thing as "Flex to Javascript communication" (or "Flex to anything communcation" for that matter). Technically, it is the Flash player/plug-in that does the communicating. Because that seemed self-evident to me, I was careless in the precise meaning of my words. My apologies for any confusion. Thanks John!
http://www.nabble.com/application-exit-event--td15646507.html
I've used ExternalInterface on a few occasions to access JS in my wrapper. I had NO idea you could form new JS from within Flex and execute it. If you scroll down a bit in that link above you can see where this is working.
Thanks for the writeup, Taylor!
re: "Flex to AJAX communication, Flex to Flex communication", it may be clearer to call it "plugin to browser communication", "plugin to plugin communication" and so on. These are the engines which actually communicate with each other, under instruction of your current Flex or Ajax.
Be sure to correctly set privileges in the HTML markup via "allowScriptAccess"... this trips up many initial experiments too.
One more thing to watch out for: The NPRuntime specs were designed for occasional messaging, rather than for heavy-duty data transfer or rapid-fire messaging... browser vary more at the edges than in the core.
tx, jd/adobe
Thank you for your comment, John. It's nice to know that someone at Adobe is aware of my blog. I've added an addendum to the posting regarding my imprecise words (though your comment pretty much covers it). Also, thank you for the heads-up regarding setting permissions in the markup and the limits in messaging performance.
Taylor
Hi Joel. Thanks for the comment. That is indeed a pretty cool use of ExternalInterface. I'll have to try that out (and perhaps post my results.)
Hi Taylor,
Thank you, I follow your way and I have a problem
It work OK on bin-debug, but in bin-release in doesn't work.
IE show error 'Object doesn't support this property or method.
Would you help me.
Thanks again.