In this article I will try and capture some of my thoughts and experience as I went through the process of getting various sites to work with files hosted on different domains. This article is for Flash Player 8 (FP8) only.
I never really thought much of cross-scripting. I always knew there were
some security involved when loading files from different domains but
never really gave it much thought. Until recently when I was stuck
between a rock and a hard place, deploying a site and nothing worked.
In my own dev environment everything worked fine yet deploying it to
the hosting server has the exact opposite effect.
In
this article I will try and capture some of my thoughts and experience
as I went through the process of getting various sites to work with
files hosted on different domains. This article is for Flash Player 8
(FP8) only.
Background
I think in order to explain cross-scripting it is important to have a look at the flash player security model. The biggest part of Flash Player security is based on sandboxes.A sandbox is a good metaphor as normally any playground sandbox is full of stuff and then some. The Flash Player security model states that whatever is in sandbox A - belongs to sandbox A. Whatever is in sandbox B - belongs in sandbox B. If sandbox A wants communication with sandbox B it requires permission unless they are in the same domain. When sandboxes reside in the same domain they are allowed to communicate freely with each other. But sometimes these sandboxes aren't in the same domain hence certain permissions are required for successful communication and interaction between these sandboxes.
Lets break that down:
- SWF file A is from domain A
- SWF file A is placed in sandbox A by flash player
- SWF file A tries to loads SWF file B
- SWF file B is from domain B thus flash player places it in sandbox B
- Communication between SWF file A and B fails silently becuase they are from different sandboxes and no permission were set to allow them to communicate.
The permission between sandboxes must be set explicitly by stakeholders of the sandbox in question. By stakeholders is meant web and user administrators and most importantly the flash application author.
The FP8 Security White paper discusses the types of sandboxes in more detail. The above was just to give you a background of how the player deals with communication between files on different domains.
The first step
How do we get two SWF files from different domains communicating? The first step is to establish what kind of communication is required. Data loading is usually the first that comes to mind but is usually solved quite quickly with a cross-domain policy file. The most problematic must be the modern workflow of different SWF's for different sections of a particular website being controlled by a main shell.Design patterns and micro-architectures requires us to develop in a more centralised fashion. MVC is a good example where all data is central to the model and thus applied through the controller to any section of the site. The data is all in one place - decoupled from view and the controller which makes it so good to use as we all know. In my experience loading/reading external data from different origins has never really introduced problems. It is when you want to interact via scripting between these files where the problem starts.
The white paper and API clearly states that when scripting across domains is needed, it is required that System.security.allowDomain( "www.mysite.com" ) should be used in the target file, i.e. the file being loaded. This will set the security permissions to allow cross-scripting. SWF file in sandbox A will be allowed to "call methods" from SWF file in sandbox B... or will they?
Here is where the tricky part comes in. The white paper states that method calls will be allowed. So here are a few simple test to check this theory.
The following examples all have the same pre-conditions:
- SWF A resides in domain A
- SWF B resides in domain B with the firstline of code being System.security.allowDomain( "*" )
- Domain B has a crossdomain policy file locaetd in the root of the webserver to allow domain A
Example 1
SWF A has the following code on the first frame:SWF B has the following code on the firstframe:
stop();
var mclListener:Object = new Object();
var image_mcl:MovieClipLoader = new MovieClipLoader();
load_bt.onRelease = function():Void { loadSWFB(); }
apply_bt.onRelease = function():Void { runApplyText(); }
function loadSWFB():Void
{
mc.createEmptyMovieClip( "sandbox_mc", mc.getNextHighestDepth() );
mclListener.onLoadInit = function( target_mc:MovieClip )
{
target_mc.output_txt.text = "SWF B loaded into SWF A\n\n"
target_mc.output_txt.text += "Applied text from SWF A in SWF B: output_txt.text\n\n";
target_mc.output_txt.text += target_mc.showOutput() + "\n";
};
image_mcl.addListener( mclListener );
image_mcl.loadClip( "http://assembleserver.com/wez/blog/examples/cs/fp8_cs_b.swf", mc.sandbox_mc );
}
function runApplyText():Void
{
mc.sandbox_mc.output_txt.text = "The text in Sandbox B was changed from SWF in Sandbox A using 'mc.sandbox_mc.text' \n";
}
stop();
System.security.allowDomain("*");
function showOutput():String {
return "Method in SWF B called from SWF A: showOutput()"; }
Well, the most obvious is the crossdomain policy file. This was loaded successfully as we wouldn't have seen any results if this wasn't the case. Using an HTTP proxy we can see that the HTTP status from the server for SWF B is 200. This basically means there were no problems when loading the file and all bytes were received successfully.

You probably already clicked on the second button "Change text in SWF B" and noticed nothing happens right? What about the third button? Anything? Ok, so let's look at the code for these to buttons more closely.
The function loadSWFB() does exactly that. Creates an instance of the MovieClipLoader and loads the target from domain B. The onLoadInit handler is invoked upon successful load and changes the output textfield "text" property to a new value. So why isn't this working in the above example? Fig .2 is what it should look like.

Fig 2: Correct result after "Load SWF B" button clicked
The flash help offers a diagram of cross-scripting and also what is allowed provided the System.allowDomain is called in the target SWF. This would be a nice diagram if it were true.

Fig 3: Flash Help Cross-scripting diagram
The one thing that does work is the last button in the example "SWF B gotoAndStop(10)". So why does a gotoAndStop() method call work but not my custom method target_mc.showOutput() I do not have the answer to this but will attempt a work-around in example 2.
Example 2
So instead of applying the textfield changes in the calling SWF (A) I am going to create one method called applyText() in target SWF B and call it from A, sending the value as a param.All that was changed in example 2 was the function to change the output textfield's value was moved to the target SWF. So why does this work? One of two things are happening here in my opinion. Moving the output_txt.text setter to the target SWF means it is now in the correct scope. Or access to the loaded SWF's textfield is denied due to cross-scripting rules broken. The latter seems unlikely unless the white paper and the Help API is not telling us the whole truth.
Design patterns & scope
The examples above were all timeline-based code. All of my projects use various design patterns. AS2 unlike AS3 is less strict with application of OO principles. Functional scope in AS2 was mainly solved by the use of a Proxy/Delegate wrapper class. Which brings me to my next point. The scope in which an instance is created will very much be influence by cross-scripting. A fellow developer mentioned that he thinks a new _global scope is created per sandbox. Therefore multiple isntances of a singleton class can be instantiated if the child SWF is located on another domain. Which brings some futher frustration to the table as you will not be able to access a generic getTextMethod() from the core classes as the instance will not be in the same scope. One way would be to pass the instance to the child via a function.Sumary
One of the major flaws for Actionscripters about cross-scripting is that the player fails silently. This makes it really difficult to pin down where the problem actually lies and debugging becomes a nightmare.Remember that reading is not a big problem, i.e. loading XML, images or video files. You wont have access to alter bitmapdata for loaded images. So no runtime colourTransforms I'm afraid.
A good solution I think will be to have everything but the language XML and preloader on one domain. So when the Singelton instance is created it is in the same scope as where the external assets will be loaded into. Therfore you should be able to access whatever you like. You might need to use the _global scope to access the instance but you at least you will have access to it.
I have spent many hours working with this problem. I can tell you it has wasted a lot of time. My advise would be if you know that different domains will be used - add a couple of days for deployment and testing. This sounds obvious but many times deployment is regarded as a one-click FTP job. With larger projects this just isn't true. The extra days comes in very handy. The ideal situation will obviously be to have your dev environment setup as an exact replica. This way testing will show any problems real quick. I hope this helps and if anyone knows anything not mentioned please get in touch. As this was for FP8 I will probably do a follow up for FP9 because AS3 has a lot better structure when it comes to scope and OO principles and we might have less to worry about.
Catch you on the flipside!


Leave a comment