Scott Morgan

Calgary Flash and Flex Developer

Nov

11

Accessing document class of an externally loaded swf with AS3

By scott

I have seen a lot of posts lately with people asking how they can access variables and methods in an external swf that is loaded at runtime using AS3. This isn’t a difficult task, but it is much different than AS2/AS1 where you could just call directly into the loaded swf using the instance chain if you were in the same security sandbox.

First off, lets create our swf that wil be loaded in at runtime. Open up your favourite actionscript editor and create a new class with the following code.

package com.scottgmorgan {
     import flash.external.ExternalInterface;
     import flash.display.Sprite;
     public class ExternalMovie extends Sprite {
          public function ExternalMovie():void {
               //nothing in our constructor right now.
          }
          public function alert(msg:String):void {
               trace(msg);
               ExternalInterface.call('alert', msg);
          }
     }
}

Now create a new FLA and set the above class as the document class. If you are not sure how to do this simply enter the class path (com.scottgmorgan.ExternalMovie) into the document class textfield found in the property panel. Lather, rinse, repeat, compile.

Next we will create the swf that will load our ExternalMovie swf we just created. Let’s jump back to our favourite actionscript editor and create a new class with the following code.

package com.scottgmorgan {
     import flash.display.Loader;
     import flash.net.URLRequest;
     import flash.events.Event;
     import flash.display.LoaderInfo;
     import flash.display.Sprite;
     public class SourceMovie extends Sprite {
          public function SourceMovie():void {
               var loader:Loader = new Loader();
               loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
               loader.load(new URLRequest('ExternalMovie.swf'));
          }
          private function onLoadComplete(e:Event):void {
               var loaderInfo:LoaderInfo = e.target as LoaderInfo;
               addChild(e.target.content);
               var swf:Object = loaderInfo.content;
               swf.alert('Hello World');
          }
     }
}

That’s it, LoaderInfo saves the day. LoaderInfo.content connects you with the document class of the externally loaded swf. Lets create a new FLA, assign the SourceMovie class as the document class and compile. Make sure the SourceMovie.swf and ExternalMovie.swf are in the same directory. The as files should be in /com/scottgmorgan/. Let’s compile the SourceMovie and you should see “Hello World” in the output window if you run the swf inside the IDE, if you run it from a browser you should see an alert dialog with “Hello World”.

Another option you have is to use the ApplicationDomain class. Using the ApplicationDomain class you can add the classes from the ExternalMovie to the SourceMovie’s ApplicationDomain. This is a great way to load in code libraries at runtime.

Lets pretend we have a large application with multiple levels of security, maybe we are creating a content management system and we need multiple permission levels. User A can only update content, User B can update content and update the site map, User C is an administrator and can do everything User A and B can do but can also access tracking information, edit user profiles, update permissions, etc. When User B logs in the application loads the site map code library (sitemapadmin.swf) and adds its classes to the main ApplicationDomain. When User C logs in the sitemapadmin.swf classes would be added to the main ApplicationDomain, for this user the application would also load the trackingadmin.swf, and useradmin.swf code libraries and add all the included classes to the main ApplicationDomain.

Let’s update our SourceMovie.as file and add the ExternalMovie class to SourceMovie’s ApplicationDomain.

package com.scottgmorgan {
     import flash.display.Loader;
     import flash.net.URLRequest;
     import flash.events.Event;
     import flash.display.LoaderInfo;
     import flash.display.Sprite;
     import flash.system.ApplicationDomain;
     public class SourceMovie extends Sprite {
          public function SourceMovie():void {
               var loader:Loader = new Loader();
               loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
               loader.load(new URLRequest('ExternalMovie.swf'));
          }
          private function onLoadComplete(e:Event):void {
               ApplicationDomain.currentDomain.getDefinition("com.scottgmorgan.ExternalMovie");
               var myExternalMovie:ExternalMovie = ExternalMovie(e.target.content);
               myExternalMovie.alert('Hello World');
          }
     }
}

There you have it. One thing you will notice is you don’t have to add the loaded swf to the display list to access its classes. Hopefully you will be able to use these techniques in future projects.

37 Responses so far

[...] along similar lines, this link that describes accessing the document class of an externally loaded swf with AS3. November 12th, [...]

[...] I just found out how to access the domain class of a loaded .swf, and I think this knowledge really helps in moving towards the ability to have complete control of that .swf.

Hi Scott,

Could you use the same method to access a media “class” in the library of a loaded swf?

newAsset=myExternalMovie.SomeAssetInExternalLibrary();

It would be convenient to have a mega library in some global object where class definitions were stored.

Thanks

Matt

Yes library items are now instances of classes so you simply have to instantiate the library item like so.

ApplicationDomain.currentDomain.getDefinition(“com.scottgmorgan.ExternalMovie”);
var myExternalMovie:ExternalMovie = ExternalMovie(e.target.content);
myExternalMovie.alert(‘Hello World’);

var test = new TestSymbol();
addChild(test);

Inside your ExternalMovie library open the linkage properties and set the class to something like com.scottgmorgan.TestSymbol and that should do it. I have uploaded an example of this here if you would like to take a look.

I wanted to have communication between child swf and parent swf such that child swf use object from the classes available in parent.
Any solution for this …

@cksachdev Once it is added to the current domain you can pass a reference of the parent object a setter in the child swf. Something like this:

myExternalMovie.parentClass = this;

That is the easiest way, you could also use a singleton and just instantiate an instance of the parent class in the child. Once you have loaded in the child and added it to the currentDomain you can do anything…as long as you are in the correct flash security sandbox.

Hi Scott,
I’ve come across a problem with movieclips that are loaded using classes within external swfs… and hoped you might have a solution.

Heres what happens:
- SWF A loads SWF B
- SWF A then adds a new Asset1() from SWF B using ApplicationDomain
- Asset1 has a movieclip within it called box_mc
- box_mc has a stop() on the first frame – but it doesn’t stop!

The first frame of box_mc doesn’t trace() either.

A stop() on the second frame works – but not the first!!

Here is an example

Any advice or workaround for using classes across swfs would be a great help!
Thanks :)

Hey. Thanks for the code snippet above that really helped. I have hit another problem though and it’s starting to bug me.

Basically I have created a game in flash which contains a fla file and many .as files.

I have also created a simple flash website which is a flash file and one Main.as file.

I have used the above code to load the game up on the website when the correct button is clicked which is works but does have a couple of problems.

Firstly I can’t position the loaded swf (game) from the website. It places the game in the top left hand corner. However if i go to the game code and position objects directly in their then they move on stage. SO it’s as though the swf contents ahs been moved to another stage rather than the swf as a single file?

Another thing that makes me believe this is that in the game i have objects that move acros the screen but this does mean that it some poarts of it sometimes go out of the stage. When the game runs by itself this isn’t a problem becuase you only see what inside the stage size. When i load the game into the website the objects that move off the stage slightly don’t get hidden when they leave the game borders. Its as though the individual compenents are playing in this new stage ( the website ).

So.. :) my question is. Is there a way to get aorund this so i can position the swf as a whole from the website and be able to stop seeing parts of objects that are outside of the loaded game stage?

Many Thanks
Stu

@Stuart – Not sure I get exactly what you’re talking about but it sounds like a mask would fix your problem. If the parent swf’s dimensions are larger than your child swfs (game) dimensions the stage size inherits the size of the parents stage size which is ultimately set by the width and height of the swf object in the html.

Right before you call addChild(e.target.content) or however you are adding the swf to the displaylist you can do something like this e.target.content.x = 105; e.target.content.y = 50;

Or after you add it to the display list you could do something like this:

this.addChild(e.target.content);
this.getChildAt(this.numChildren-1).x = 105;
this.getChildAt(this.numChildren-1).y = 50;

I hope that answers your questions.

Hey Scott,

Cheers for the reply.

Yeh I have tried that and have just again with your syntax but still have no luck. If i load in a simple swf file which consists of just a .fla file. I can move it about the stage as you say using your method. But with this game I have no control over it’s position from the preloader( website ). So in the game all th egame entities are positioned using code. So say a power bar statrts off at 50.0, 50.0; then it will position at 50.0, 50.0 from 0,0 of the website ( so the game is in the top left corner) and no matter what i do from the preloader(website) i cannot reposition it, even though in game this position is only set once.

What did you mean by mask, or is that what you described?

Yeh about what you said about loading a smaller swf into a larger swf then the loader takes on the stage properties of the pre loader. Ok i understand that an dthat is the case here. Is there a way i can make it so it doesn’t take on the preloader stage properties? A way around this problem is to place the game behind a hole in the website or something so any object leaving the game stage wont be seen as its blocked by the website but thats just a bodge.

Cheers
Stu

Actually,
ExternalInterface in first example is not needed at all.
And why is ExternalInterface.call(‘alert’, msg); used for.
ExternalInterface is intended for AS/JS communication.
You can access child’s properties/methods without any additional logic. You do it, as said, just through loaderInfo.content.

@Sinisa – ExternalInterface was just shown as an example, has nothing to do with my approach to access a class from another loaded swf. If the example is run in a browser this just proves it is working by firing a javascript alert for those who aren’t tailing their flashlog.txt or running a flash tracing plugin. Also using the loaderinfo.content you can do a lot of things but if you are planning on loading from a different domain or if you want to access library elements from other elements in the parent swf you will need to add the contents of the loaded swf to the ApplicationDomain and/or the SecurityDomain.

I have a Flex flv player application that shows a list of video thumbnails alongside an externally loaded player that was created using as2. I’m communicating between the application & player via Local Connection. This works great.

Here’s my problem… I’ve included this application in a parent swf movie. The flex application is loaded when someone clicks a “watch videos” button. When someone clicks to another area of the video, I can’t get the video to stop playing/unload… you can still hear it in the background.

I’ve tried several methods but can’t get the flex player application to unload & stop any playing videos.

Here’s how things are set up…
Main timeline has a frame with a moviePlayer instance an flvPlayer movie from library…
moviePlayer loads an external flvplayer.swf via myLoader:Loader…
flvplayer.swf is a flex application that loads vidclip.swf & communicates with it via toFlash_lc:LocalConnection.
On the main timeline, when someone clicks away from the player, I need to fire toFlash_lc.send(‘lc_from_flex’, ‘setPath’,”) from within the flex application to send a blank url to the flash player. Then unload the flex application.

Thus far, my gazillion attempts have failed. Any suggestions?

@scott,

Very nice example, my question is lets say you have two swf’s one containing movieclips the other bitmaps. Using your example once you load in both swf’s using one loader how can you tell Flash which swf to look into to grab specific classes from that swf?

This would have to be dynamic so that you could load in as many swf’s as you want but still be able to tell Flash which swf to look in for a specific class.

Thanks.

Thanks scott, very useful information on my not-so-painful-as-i-tought transition from AS2 to AS3

Great Post! Saved my life. I was scrambling around trying to figure out the right way to do this in AS3, but was getting nowhere.Thanks for posting this.

Awesome post! Sheesh, this AS3 stuff is tough…

You rock. Ive been triing to get this answer everywhere. How to access object in a loader loaded swf. It works. Thank you!!!

The code works but now that I am using this method the pages I loading are running into problems.

I have the line at the top of my file to be loaded.
var MC:MovieClip= MovieClip(parent.parent.parent); this way I call something from the swf that loads this page. example
MC.showme();

Problem is now I keep geeting a error 1009 and the only way it works is if I put it down in the code or run some kind of delay. Its like the page takes time to reconize the parent.

Any Idea whats happing?

[...] implement this I used the Flash 9 Loader class and the ExternalMovie [...]

Great job, Scott! Thanks for a terrific explanation and helpful examples. Keep it up!

Thanks.. life saver.. couldn’t get the Child SWF to speak to the parent…
Works like a charm

thanks for this post with helpful examples.

[...] Even more interesting [...]

hi

i’ve s simpler doubt. i have a swf with a button with rollover,click and out functions . works fine isolated.
But, when i load this swf in the main swf, the events aren’t dispatching…

Do you know why? how do i fix it?

thanks

I’m trying to find a way to get the document class without knowing the actual class path.

For example you have this line:

ApplicationDomain.currentDomain.getDefinition(“com.scottgmorgan.ExternalMovie”);

But in my situation I’m never going to know the exact class that is used. Is there a way I can retrieve that info as well? This is fantasy code and I’m sure this doesn’t really make sense but hopefully this will give you an idea of what I’m after:

var docClass:String = Application.currentDomain.getDocumentClass();

ApplicationDomain.currentDomain.getDefinition(docClass);

Any ideas?

Doesn’t this way of doing it kind of defeat the purpose of dividing the application up in smaller swfs? By datatyping the external SWF you are effectively ensuring that the class and any of its embedded assets are compiled into the loading swf, so using this method for loading external asset libraries would not be so great.

Or am I wrong?

I had the same issue that some folks are having about timeline scripts not showing up.

The problem is the that the LOADER swf is importing the class only- it has no idea that there is timeline actionscript. So when it loads it won’t fire the timeline script of the LOADED.

To solve you either need to have the LOADER reference the LOADED by Interface, or you could have the LOADED swf extend the class which the LOADER swf imports.

heres a good explanation:
http://3lbmonkeybrain.blogspot.com/2008/02/of-document-classes-and-timeline-code.html

This was a monster of an issue for me yesterday, I wasted like 5 hours.

Hi, I have a question that I am hoping you can help me out with.

I am creating a portfolio of my work using flash cs4 and I have a menu on the left side of my original file and I want to load a swf file into my AS3 flash file to the right of this menu bar on a certain frame so when someone clicks the button it takes them to that frame where the file will be loaded. But so far I can only figure out how to load it on top of the original flash document (covering the menu bar).

Do you have the code or know the way to place the swf file in a certain place on the original document? Thanks so much, I am learning as3 still and I only know the old way in as2 to load into an empty movie clip.

Hi, any way for do it on flex???

Hello,

Thanks for your posting which helped find out a solution for my problem.
IF you WANT TO EXECUTE A FUNCTION LOADED IN CHILD ON THE STAGE:
SAY A.SWF — LOADS— B.SWF
A NEEDS TO EXECUTE A FUNCTION IN B HERE IS THE SOLUTION

HERE THE FUNCTION IN B IS
function alert(msg:String):void {
trace(msg);
}

THE ONLY THING TO DO IS IN YOUR FUNCTION CALLED FROM A MOVIE … DO THIS
var swf1:Object=myload.content;
swf1.alert(“yoyo”);

I have been reading on post for 2 days to finally get part of it here.

Great Thanks

Vincent Rose

really usefull and just what I needed.
Now i can ‘design’ some classes on the timeline instead of designing the movieclip in code. saves a LOT of time (:

~Marco

thanks for posting this.

but for me, i will never understand, why as3 is so much clearer. running in problems like this one – which is constant thing when you move from as2 to as3 – is a nightmare.

moving along with flash from plugin 3, for me, this is a break which will drive so many developers away, coming from the visual part. people that drove the flash thing up this point.

[...] with them ignoring each other.

With this I can access the variables of the loaded swf from the main class, but not the other way around. I need to set a static var in document class from an externally loaded swf. Cant seem to figure it out yet

Done! I dont think it is logical to have to go through this

In the document class I have a setter called PanelX that sets the value for the variable panelX, and in the loaded swf, this

var swf1:Object=loaderInfo.content; //taken from Vincent Rose post
var test:MovieClip=MovieClip(swf1.parent)
test.PanelX=5000

Not neat but works. Even when the variable was public, i still couldnt set it as
panelX=5000
Beats me

Leave a comment