Lab: Adobe Captivate-to-Flash ActionScript Communication

Workaround 2: Use Flash's ExternalInterface class

How it works

Captivate can make JavaScript calls; these JavaScript calls can be used to relay pre-defined instructions to a Flash-based SWF.  The relay mechanism is a Flash class named ExternalInterface.

The basic chain of events looks like this:

  1. Captivate invokes a JavaScript function located in the HTML…
  2. … which in turn invokes a Flash ExternalInterface callback located in the HTML…
  3. … which in turn invokes an ActionScript function located in the Flash SWF

 

Diagram of JavaScript-ActionScript flow between files

 

For this demonstration, a Captivate SWF will be configured to call a single JavaScript function named unloadMe() at the end of the last slide.  We will utilize ExternalInterface to prompt the Flash "player" SWF to unload the Captivate SWF.

Important notes

  • ExternalInterface requires Flash Player 8 or higher.
  • If run locally (from a CD or hard drive), your Flash Player security settings must be edited to allow files in that particular directory to communicate with each other. The demonstration will not work locally if these settings are not enabled. Here's how Adobe explains it:
    • Security note: For local content running in a browser, calls to the ExternalInterface.addCallback() method will only work if the SWF file and the containing web page are in the local-trusted security sandbox.

Files required

  1. HTML file.
  2. Flash "Player" FLA.
  3. Captivate file.

 

Instructions

1. In player.fla, create the function you'd like the Captivate SWF to invoke

Open player.fla and write the function that the Captivate SWF will invoke. The function should be contained in the first frame of the FLA's main timeline. For this demonstration, we'll write a function named "unloadSWF" that will unload the Captivate SWF from the player.

function  unloadSWF(){
   unloadMovie("swfHolder");
}

 

2. Add the ExternalInterface code to player.fla

Add this line to the top of the frame script in player.fla's first frame:

import  flash.external.ExternalInterface;

This tells Flash that we will be using its ExternalInterface class, ensuring our ExternalInterface callback will be properly supported.  Now add the callback:

import flash.external.ExternalInterface;
ExternalInterface.addCallback("unloadMe", this,  unloadSWF);

Screenshot of Flash's "Actions" window

The two most important parameters in this line are also the two most confusing.  The first parameter, "unloadMe", is the name of the JavaScript function that will be called in the HTML. It's a string and must be surrounded by quotes. The last parameter, unloadSWF, is the name of the ActionScript function that will be called. It's an actual function call and therefore shouldn't be surrounded by quotes.

In case you're wondering, the middle parameter, this, is simply stating that the callback belongs to this movieclip (in our case, it's the main timeline). You shouldn't need to change this to anything else.

 

3. Add the loadMovie code

While we still have player.fla open, let's add the loadMovie code we'll need to automatically load our Captivate SWF for us. We also need to add the stop() command to prevent the player.swf from looping.

loadMovie("sample-captivate-movie.swf",  "swfHolder");
stop();


Screenshot of Flash's "Actions" window

 

4. Publish player.fla

Publish the FLA file.  Turn off the 'publish HTML' option, since we won't be using any of the HTML generated for this SWF. Also make sure the SWF is published as Flash Player 8 or greater (ActionScript 2.0) or else the ExternalInterface code will fail.

Note: Even though this demonstration uses ActionScript 2.0, you can also use ActionScript 3.0; you'll just need to adapt the ExternalInterface code to its newer ActionScript 3.0 syntax.

 

5. Add the JavaScript call to the Captivate file

Open the Captivate file sample-captivate-movie.cp.  Go to the Slide Properties for slide two. Select the Execute JavaScript from the Navigation drop-down menu.

Screenshot of Captivate's "Slide Properties" window

The JavaScript window will appear.  Any JavaScript entered here will be executed at the conclusion of this slide. For our demonstration, we only need to add a single function call:

unloadMe();

Screenshot of Captivate's "JavaScript" window

Click OK to close the JavaScript window, then click OK to close the Slide Properties window. The JavaScript is now a part of your Captivate movie.  Save the Captivate file, but don't publish it yet.

 

6. Turn off skinning

Since this Captivate movie will be loaded into another SWF (our custom player.swf), it's safe to turn off Captivate's skinning feature.  Go to Project > Skin and uncheck both "Show playback control" and "Show borders".

Screenshot of Captivate's skin editor options

 

Note: If you preview the new Captivate SWF in Captivate or anywhere outside of the player SWF, nothing will happen when Captivate executes your JavaScript. This is because the function unloadMe() does not exist in the Captivate file; the function is stored in the HTML file. It can only be executed if the Captivate SWF has been loaded into the player SWF.

 

7. Publish the Captivate file

Publish with the following settings:

  • Flash SWF as the output type.
  • Uncheck "Export HTML" (you will get a warning, but it's safe to ignore it).
  • Output SWF as Flash Player version 8 or higher.

 

8. Add the necessary JavaScript to HTML file

To have Captivate's unloadMe() JavaScript command properly relayed to the player SWF, we need to configure the JavaScript contained in the <head> of the HTML file.  Remember, the JavaScript in the HTML file is the relay point; the chain of events is:

  1. Captivate invokes a JavaScript function located in the HTML,
  2. which in turn invokes a Flash ExternalInterface callback located in the HTML,
  3. which in turn invokes an ActionScript function located in the Flash SWF.

We'll start by creating an empty function that matches the name of the function we used in Captivate:

function unloadMe() {

}

Next, we'll add the ExternalInterface callback to the function. For the callback to work, we need JavaScript to identify the player SWF as an object.  We can do this by using the very common and widely supported document.getElementById() DOM method.

Note: For this demonstration, the player SWF's ID has already been defined as "captivatePlayer" in the SWFObject embedding code.

function unloadMe() {
   var player = document.getElementById("captivatePlayer");
}

Once the SWF has been identified as an object by JavaScript, we can implement the "unloadMe" callback we defined in the FLA file:

function unloadMe() {
   var player = document.getElementById("captivatePlayer");
player.unloadMe();
}

That's it for the JavaScript!  It's pretty straightforward.  If you prefer, you can also use the following shorthand syntax:

function unloadMe() {
   document.getElementById("captivatePlayer").unloadMe();   
}

Don't forget to save the HTML file.

9. Test it!

Now that your files are ready, test them out! Make sure the following files are in the same folder:

  • index.html
  • player.swf
  • sample-captivate-movie.swf

Open index.html in your web browser.  The sample Captivate movie should automatically load.  Click the Click here to go to the next slide button. You should see the countdown, followed by the SWF unloading itself.

Reminder: If run locally (from a CD or hard drive), your Flash Player security settings must be edited to allow files in that particular directory to communicate with each other.

 

Workaround notes

Pros

  • Less bulky/tedious than imported SWF solution.
  • Easy to quickly add or edit customs scripts.
  • Not restricted to nested SWFs; a Captivate SWF using ExternalInterface can communicate with any properly configured SWF contained in an HTML page.

Cons/limitations

  • Requires Flash Player 8 or greater.
  • Relies on JavaScript being available in the browser.
  • JavaScript calls are bound to Captivate objects and/or events.
    • No multitasking or queuing
    • Can't 'stack' actions on objects such as buttons
  • Is difficult to implement in local environments (such as on a hard drive or CD-Rom) due to Flash Player's security restrictions.

 

< Go back to Workaround 1