Thursday, July 13th, 2006 |
|
SWF9 to SWF8 Communication - EI not LC - Part 2 |
Below is an example that contains a SWF9 that was written in Flex (AS-only) and contains two textfields. The SWF9 loads a SWF8 that also contains two textfields. The top textfields are input fields. The left-hand contents belong to the SWF9 and the right-hand contents belong to the SWF8. When you type in the top-left textfield, which resides in the SWF9, the text will get sent to the bottom-right textfield, which resides in the SWF8. When you type in the top-right textfield, which resides in the SWF8, the text will get sent to the bottom-left textfield, which resides in the SWF9.
Check it out the example.
The following is the code involved in this example.
Here’s the code in the SWF9:
package
{
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.external.ExternalInterface;
import flash.text.TextField;
import flash.net.URLRequest;
import flash.display.Loader;
public class SWF9_SWF8_Comms extends Sprite
{
public var tfIn:TextField;
public var tfOut:TextField;
public function SWF9_SWF8_Comms()
{
stage.align = 'TL';
stage.scaleMode = 'noScale';
tfIn = new TextField();
tfIn.border = true;
tfIn.background = true;
tfIn.multiline = true;
tfIn.wordWrap = true;
addChild(tfIn);
tfOut = new TextField();
tfOut.type = 'input';
tfOut.border = true;
tfOut.background = true;
tfOut.multiline = true;
tfOut.wordWrap = true;
addChild(tfOut);
tfOut.addEventListener(Event.CHANGE, textChanged);
tfOut.x = 10;
tfOut.y = 10;
tfOut.width = 200;
tfOut.height = 100;
tfIn.x = 10;
tfIn.y = tfOut.y + tfOut.height + 10;
tfIn.width = 200;
tfIn.height = 100;
tfOut.text = 'Type text here';
tfIn.text = 'Text from SWF8 will show here';
ExternalInterface.addCallback('fromSWF8', fromSWF8);
var u:URLRequest = new URLRequest('swf8.swf');
var ldr:Loader = new Loader();
ldr.load(u);
addChild(ldr);
}
private function textChanged(e:Object):void
{
ExternalInterface.call('SWF9_SWF8_Comms.fromSWF9', tfOut.text);
}
public function fromSWF8(a:String):void
{
tfIn.text = a;
}
}
}
And here’s the code in the SWF8:
import flash.external.ExternalInterface;
createTextField('tfIn', 1, 0, 0, 10, 10);
tfIn.border = true;
tfIn.background = true;
tfIn.multiline = true;
tfIn.wordWrap = true;
createTextField('tfOut', 2, 0, 0, 10, 10);
tfOut.type = 'input';
tfOut.border = true;
tfOut.background = true;
tfOut.multiline = true;
tfOut.wordWrap = true;
tfOut.addListener(this);
tfOut._x = 340;
tfOut._y = 10;
tfOut._width = 200;
tfOut._height = 100;
tfIn._x = 340;
tfIn._y = tfOut._y + tfOut._height + 10;
tfIn._width = 200;
tfIn._height = 100;
tfOut.text = 'Type text here';
tfIn.text = 'Text from SWF9 will show here';
ExternalInterface.addCallback('fromSWF9', this, fromSWF9);
function onChanged()
{
ExternalInterface.call('SWF9_SWF8_Comms.fromSWF8', tfOut.text);
}
function fromSWF9(a)
{
tfIn.text = a;
}
The code that does the real work here is ExternalInterface.addCallback and ExternalInterface.call. In Part 1 we saw how we could communicate with JavaScript from Flash and back. In this case we are doing the same thing, only without having to write any JavaScript.
The trick is to include the ID of the object tag in the call method. Doing that means you don’t need any JavaScript on the page. Firefox does display a warning in the JavaScript console saying that you should be using getElementById instead of directly targetting the object ID, but it does work.
Alternatively, you could drop-in a little JavaScript to use a proper W3C DOM call. If you’re having issues in some browsers, then maybe that’s why. The example posted here works for IE6 and Firefox 1.06 (I know, I know, I’ll upgrade …).
I’m not sure how much time I’ll have to spend on this, but an obvious take is to build a set of Proxy/__resolve objects/classes that allow real transparency between the SWFs.
Hopefully this is useful for someone.










Thank you for these explanations, very useful… but… if the swf8 file is loaded from a different domain, it seems that the communication from swf9 to swf8 doesn’t work anymore… any ideas?
Thank you.
Useful indeed! I’m curious if the ExternalInterface solution is applicable when the application is not running within an embedded flashplayer on a web page. LocalConnection works even if running in the standalone flash player or within an OCX component in a .NET application (I’m not sure about an AIR app).
Great article. Lawrence
@Paolo
The communication in that case is limited by Flash Player security. You can get around this by setting the allowScriptAccess parameter to always. In my example I left the default of sameDomain. That should allow both SWFs to talk to JavaScript, and thus, each other. You might also need a crossdomain.xml file for the remote SWF. I haven’t tested this yet.
@Lawrence
Thanks. Yes and no. ExternalInterface is available to the container. If you are building a VB, C++, C#, etc., application and embedding the Flash Player within, then your app can receive an event when the Flash Player is trying to communicate using ExternalInterface or FSCommand. FSCommand passes data out of the Flash Player as a string with no encoding. ExternalInterface passes data out in XML format, and expects data in to be formatted similarly. With EI you have to encode and decode the XML yourself.
So, it is possible to have EI work in your own application outside of the browser. In fact you would have little parsing to do if all you wanted to do was have the container act as a local loop.
For the standalone Flash Player it is not possible. EI isn’t available from the standalone Flash Player. You will receive a runtime error if you try and execute using EI. There’s a property on ExternalInterface (available in AS3) called available that you can use to distinguish whether or not this type of communication is allowed.
Some notes on the different methods:
LocalConnection would be the slowest and most limiting, imo. It has a 40KB data limit and tends to be slow and unreliable. It is asynchronous. However, it can be used to connect to another Flash Player instance, regardless of where that Flash Player is contained. It’s limited by the fact that a connection is only between two instances. A third instance trying to communicate to one of the other two will fail. You also can’t communicate (easily) with the container in this way.
EI is not incredibly fast and does require you to encode/decode XML-safe data. It is, however, the only mechanism for getting data back into the AVM2 without using sockets. EI is synchronous, stopping AS execution until the container returns from FlashCall (the event).
FSCommand is by far the fastest, since there is no encoding/decoding. But it is only one-way communication. FSCommand is asynchronous, since it is not executed to the container until all other ActionScript in the same frame has executed. Therefore the fastest data can be returned to Flash is in the next frame.