Update April 7, 2008: I’ve written a new AS3 class named LegacyCaptivateLoader that uses ExternalInterface to bridge the AS3 SWF and the Captivate SWF. Check it out.
I guess I’m late to the party, but I only recently realized that although a Flash Player 9 SWF can load an older Flash Player 6/7/8 SWF, it can’t communicate with it.
(In my defense, since we haven’t really started using ActionScript 3 at work yet, I’ve been a bit slow in switching to AS3. The leap from AS2 to AS3 is pretty daunting, so I’m sure I’m not the only one dragging my feet!)
Turns out the mechanism that processes the ActionScript (the ActionScript Virtual Machine, or “AVM” for short) has been rebuilt. Flash Player now ships with two unique ActionScript processors: AVM1 for legacy ActionScript 1 & 2 SWFs, and AVM2 for ActionScript 3 SWFs. Without getting overly technical, this enables AVM2 (Flash Player 9 SWFs) to be exponentially faster than AVM1 (Flash Player 8 and lower SWFs).
As you can imagine, many Flash developers — like you and me — still need to load old SWFs into a new Flash Player 9 (ActionScript 3) user interface. For instance, many Flash-based e-learning courses load ‘content’ SWFs that were created a couple of years ago with Flash MX (7) or Captivate. No one wants to recreate or republish a few years’ worth of development files.
To accommodate people who still need to use their older SWFs, Adobe configured Flash Player to allow AMV2 SWFs to load the older AVM1 SWFs in a virtual sandbox. But, as I mentioned, there’s a catch: these AVM1 SWFs cannot communicate with the parent AVM2 SWF.
This is a very big problem for many Adobe Captivate users. Adobe didn’t wait for the Captivate development team to convert Captivate to AS3, which means Captivate users are still publishing AS2 SWFs on a daily basis. A large number of Captivate users ‘play’ their Captivate files in custom Flash-based course interfaces. If they want to use a newer AS3 interface to control their Captivate SWFs (play, pause, etc.), they’re out of luck.
I guess you can’t blame Adobe for not updating Captivate’s codebase; Captivate has probably had the same codebase since early versions of RoboDemo, and converting to AS3 would probably require a complete overhaul of the product. No small task.
Anyway, I’ll get to the point: I researched the different methods available for AVM1 to AVM2 communication, and discovered there are a few workarounds that can enable the AS3 SWF to communicate with the AS2 SWF. I spent the entire day whipping up a Captivate-specific proof-of-concept, which can be viewed here.
Because LocalConnection requires the old SWF to have specific LocalConnection code inside it, we can’t use LocalConnection on Captivate SWFs without a little help. I was able to use a proxy SWF to load the Captivate movie.
I’m not ready to explain the code and hand out the source files, but I hope this proof of concept can help others out. The short version is:
- A ‘player’ SWF (AS3) loads an AS2-based ‘proxy’ SWF. This proxy SWF is configured with custom LocalConnection settings allowing it to send and receive commands from the AS3 player.
- The proxy SWF loads the Captivate SWF. Since the proxy SWF and Captivate SWF are both AS2, they can communicate with each other using the famed ‘Captivate variables’.
Thus the AS3 SWF sends instructions to the proxy SWF, which relays the instructions to the Captivate SWF. Conversely, the Captivate SWF sends data (frame count, current slide, etc.) to the proxy SWF, which then sends the data via LocalConnection to the AS3 SWF.
BTW, using LocalConnection to bridge AVM1 and AVM2 isn’t an original idea… many people have blogged about these concepts over the last year or two, and had some good tips (see my references at the end of this post). There are even a few functional commercial and freeware products out there.
I decided to develop my own method out of curiosity, and because most of the existing products are overly complicated, designed to handle way more than my dinky little Captivate files. Plus I wanted to create a system that would have the ‘Captivate variables’ built-in, so it will be plug-and-play with any Flash-based Captivate loader.
There are some very big caveats when using LocalConnection to bridge AVM1 and AVM2 SWFs; these caveats are big enough to make me question just how far I want to go with this project.
Caveat #1: LocalConnection is asynchronous. This means it can’t return values, and it may not kick in as soon as you’d hoped. I learned firsthand that LocalConnection worked much faster in my local environment than it did after I uploaded it to the server.
Caveat #2: LocalConnection works independent of the browser, and can only have ONE active connection per unique LocalConnection session. For instance, if I create a course that uses a LocalConnection named “FlashToCaptivate_LC”, I can only have one instance of that course running on my computer. If I open a second instance of the course, regardless of which browser it’s in, or whether or not the course is local or online, the second course will return a LocalConnection error because the connection named “FlashToCaptivate_LC” is already in use. Think of it as a phone number without call waiting. If someone is on the phone and you try calling, all you’ll get is a busy signal. That’s LocalConnection.
What do you think?
I’d love to hear any feedback you might have about this topic, including whether or not any of you have tried LocalConnection yourselves.
Here are some good resources/discussions about the topic if you’d like to learn more (no particular order):
- Flex Controlling Flash by Jesse Warden
An example of communication between SWF files using LocalConnection(an Adobe TechNote) [link no longer available] Using Flash 8 SWFs with Flex 2 Applications(an Adobe TechNote) [link no longer available]
- ActionScript.org: Local Connection by Jesse Stratford
- SWFBridge: Easier AS3 to AS2 Communication by Grant Skinner
FlashInterface: ActionScript Virtual Machine Communication[link no longer available]