Over at The Question Room (or @thequestionroom) the banditos received a bunch of tweet questions about a problem @gertjansmits was having when loading a Flex application with a SWFLoader and casting it to an interface.
They’ve called on my help to get the answer
Download the application FXP (Flash Builder 4 project) or
Run the application (Right click and View Source)
My simple interface class, TestInterface, implements 3 functions, a simple getter/setter pair and a function called sayHello.
TestInterface.as
1 2 3 4 5 6 7 8 9 | package com.flexdaddy { public interface TestInterface { function get givenName():String function set givenName(str:String):void function sayHello():void; } } |
You first need to make sure the Application you are loading implements this interface. My root application tag looks like this:
LoadedApp.mxml
1 2 3 | <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" implements="com.flexdaddy.TestInterface" width="100%" height="100%"> |
And then in a Script block I make sure to implement all three functions specified above.
LoadedApp.mxml (LoadedApp.swf)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" implements="com.flexdaddy.TestInterface" width="100%" height="100%" > <mx:Script> <![CDATA[ import mx.controls.Alert; private var _givenName:String; public function set givenName( str:String ):void { _givenName = str; } public function get givenName():String { return _givenName; } public function sayHello():void { mx.controls.Alert.show( "Hello " + givenName ); } ]]> </mx:Script> </mx:Application> |
Now when loading the LoadedApp application when using a SWFLoader in the main application we first need to do the following:
This will make sense in the code below. You’ll also notice that after we cast the loaded Flex application to TestInterface we can directly call on any methods or properties implemented from the Interface. In this case I set the givenName and call the sayHello function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script> <![CDATA[ import mx.events.FlexEvent; import mx.managers.SystemManager; import com.flexdaddy.TestInterface; private var myLoadedApp:TestInterface; protected function swfloaderComplete(event:Event):void { // the SWF Loader has complete but we need to wait for the // Flex application to load var loadedApp:SystemManager = event.target.content as SystemManager; loadedApp.addEventListener( FlexEvent.APPLICATION_COMPLETE, loadedAppComplete ); } protected function loadedAppComplete( event:FlexEvent ):void { // cast the loaded application to the Interface myLoadedApp = event.currentTarget.application as TestInterface; myLoadedApp.givenName = "Flex Daddy"; myLoadedApp.sayHello(); } ]]> </mx:Script> <mx:SWFLoader source="LoadedApp.swf" complete="swfloaderComplete(event)" /> </mx:Application> |
And that’s it!
Download the application FXP (Flash Builder 4 project) or
Run the application (Right click and View Source)
Related posts:
7 Responses to Cast a loaded Flex Application to an Interface
@gertjansmits asked a bunch of Q’s about loading a SWF with SWFLoader and casting it to an Interface | The Question Room
January 19th, 2010 at 3:36 pm
[...] Over at Flex Daddy Andrew Spaulding (@spaulds) has written a post titled “Cast a loaded Flex Application to an Interface”. [...]
Gertjan
January 19th, 2010 at 7:02 pm
Hi Andrew!
Thanks for your post and your effort. I really appreciate it!
But, what you are describing here is exact what I came up with. But it threw a SecurityError.
The .swf that I’m loading is located on a different domain than the parent. So I tried some security settings (I really should dive in more, I know) and ended up with:
_swfLoader.trustContent = true;
_swfLoader.loaderContext = new LoaderContext( true, null, null );
(and as it turns out trustContent is ignored when loaderContext is manually set)
This worked fine when I tested my main .swf on my machine (still grabbing the loaded .swf from the www).
But online it threw a SecurityError when I tried to cast _swfLoader.content to my interface (even when I tried casting it to a SystemManager).
Now my _swfLoader just uses:
_swfLoader.loaderContext = new LoaderContext( true, null, SecurityDomain.currentDomain );
Now it throws a SecurityError offline, but online everything works as expected. (which I like!).
I hope it makes some sense… if not, (and if you’re interested) I’ll explain in more detail.
Again, thanks for your help!
Andrew Spaulding
January 19th, 2010 at 7:22 pm
Hi Gertjan,
Oh, loading from a different domain will hit security sandbox issues! You should be able to get around it like you have above… but here’s some code in a little more detail.
The code assumes you set your mx:SWFLoader id=”swfLoader”
import flash.system.SecurityDomain;
import flash.system.ApplicationDomain;
var context:LoaderContext = new LoaderContext();
context.securityDomain = SecurityDomain.currentDomain;
context.applicationDomain = new ApplicationDomain();
swfLoader.loaderContext = context;
swfLoader.source = “http://otherdomain.com/RemoteApp.swf”;
Interested to know if the above works for you. Set this up before you set the source for the SWFLoader.
– Andrew
Brett Coffin
January 19th, 2010 at 8:11 pm
Flex 4 b2 (10485) simple loading sub-app with Externalizing application classes. Does anyone has a working example ?
I am trying this with the most simple application and I am getting rte “Could not find compiled resource bundle ‘components’ for locale ‘en_US’.” ???
Tink
January 19th, 2010 at 9:53 pm
Would they be best off using a Module, instead of a full blow Flex app, inside another?
Gertjan
January 19th, 2010 at 10:00 pm
Hi Andrew,
The instantiation of my SWFLoader:
if ( !_swfLoader ) {
_swfLoader = new SWFLoader();
_swfLoader.loaderContext = new LoaderContext( true, null, SecurityDomain.currentDomain );
_swfLoader.scrollRect = new Rectangle( 0, 0, 740, 370 );
_swfLoader.autoLoad = true;
_swfLoader.addEventListener( Event.COMPLETE, playFlash );
}
_swfLoader.source = _source;
I allready did this in de beginning, only then I also set trustContent to true and used ‘null’ for security domain. This is basicly the same as your code, except the ApplicationDomain part, but that didn’t gave me an issue.
Amasio
July 3rd, 2010 at 6:16 am
Thanks very much! Works like a charm.
One small addendum: in Flex 3.5 (I’m not sure when this changed), mx.managers.SystemManager has been changed to mx.managers.ISystemManager. Once I made this change, it worked without a hitch.
Great job!