ExternalInterface: Flex + Javascript Get Downright Cozy

| 5 Comments

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.


browser-html-flex.png

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)

ExternalInterface.png

Javascript Calling Flex

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):

To call Javascript functions from inside of Flex, you need to first have a function in the wrapper (or imported/included in the wrapper) which you will then use the ExternalInterface.call() function to invoke. This function can take a variable number of parameters (i.e. 0...n).

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

One clever thing that you can do through the ExternalInterface is to use the "eval()" Javascript function to run an expression that you've written inside your Flex application. This gives you the freedom to write basic Javascript expressions right in your Flex application and have them run inside the HTML wrapper.

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!

5 Comments

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.

Leave a comment



About this Entry

This page contains a blog entry by Taylor Bastien published on February 5, 2009 11:18 AM AD.

Clever Flex Binding With Ternary Operators was the previous entry in this blog.

For Ottawans interested in Flex... and beer. is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.