ApplicationDomain clarifiation needed - actionscript-3

I need some clarification on this subject as I just ran into an issue with loading swfs into a reused loader object.
So lets say I have 3 SWFs.
Main.swf
childA.swf
childB.swf
Main.swf has a loader object in it that gets reused (myloader.load("childA.swf")) and childA or childB swf will be loaded via user interaction.
Both child swfs have a com package with a class in that package called config.
The config files are different files for both classes just named the same.
both child swf also dispatch an event that the Main listens for
Now the problem I had was if childA was loaded first then after childB was loaded it would still show as childA. Basically, whichever one got loaded into that loader first would be the winner.
This drove me nuts as nothing I did would cause the swf to unload. Not until I found the following code.
var appDomain:ApplicationDomain = new ApplicationDomain();
var context:LoaderContext = new LoaderContext(false, appDomain);
_contentPanel.load(new URLRequest(str), context);
I stumbled over this code on a post somewhere talking about how to truly unload a swf. Apparently, This also applies to how to truly load a swf.
As you can see a new appDomain is created and assigned to the context when loaded.
This works like a dream I can now load and unload all day long.
My confusion is the event that the child dispatches still works, when I don't think the Main swf should pick it up due to it not being in the same appDomain.
I mean shouldn't the event be blocked?

Unloading a SWF
The Loader class provides Loader.unload() (or after Flash Player vers. 10 - Loader.unloadAndStop())
Problem with the second loaded SWF being overridden by the first
Objects that are stored in ApplicationDomains are stored by their class-name and I wonder whether the class names of the loaded SWFs (or their children) are overriding. Even if that isn't the case; why not use a new instance of the Loader for each object being loaded?
How the Main SWF can pick up both children from another application domain
The Main SWF will be able to work with the new (loaded) application domains because they are child-domains of the Main SWF's (See ApplicationDomain.parentDomain). The Main SWF's domain will be the 'system domain' and the new instances will be loaded below it.
Splitting the loaded SWFs from the Loader
Ideally you want to have access to the SWF data irrelevant of the state of the Loader. You can do this by accessing the root movieClip of the SWF once loaded and create a new instance with
var rootClipClass:Class = ApplicationDomain.getDefinition("[InsertYourRootClipName]") as Class;
var rootClip:MovieClip = new rootClipClass();
At that point you can unload the loader and work with your fresh instance cleanly.
Further reading
Difference between Loader.unload() and Loader.unloadAndStop()
Working with Application Domains - Adobe Docs
Loader class reference
ApplicationDomain class reference

Related

Is it possible to put a Class linked to a document (aka Document Class) into a RSL and still have it as Document Class?

Firstly, my environment. My question is if it's possible to do so using Flash Professional and not Flex, FlashBuilder or the like (I don't have those environments at the moment).
Here is the thing: we have several .fla files with a Document Class set. The .as file with the class is shared with all those .fla files, so all them have this same class set as their Document Class. The point is that because of that the Class is compiled into each generated .swf files, and as result any changes made to the Class would require all the .fla files to be recompiled.
After some research I found out about RSLs. But I'd like to know if it's possible to have the class as RSL while also having it as Document Class for each file? It would ease stuff because in case a change needs to be done in the class we wouldn't need to recompile each file, or regenerate each .swf files.
Aditionally, if it's possible, how could I implement a RSL through Flash Professional? All the documentation I have found shows that through Flex and others.
Please let me know if I wasn't clear enough.
As already pointed out, you cannot use a RSL with a document class. However, you can put classes in an RSL and load those at runtime likely achieving what you desire.
Here is a very simple example:
1. Create the RSL assets:
Let's say you have a class that changes from time to time and you want to load it's functionality at runtime:
//TestyMcTestFace.as
package {
public class TestyMcTestFace {
public static function go():String{
return "I'm Testy McTestFace";
}
}
}
So, what you can do, is make a new AS3 project in FlashPro/AdobeAnimate CC. Link up your class file so your project finds it (in this case I just put my TestyMcTestFace.as in the same directory as the new .fla I created).
Put a reference in the timeline code to the class(es) you want included. Without this reference the class will not get exported in the resulting swc/swf.
So for this case, I have a new AS3 project with just one line on the first frame of the timeline:
TestyMcTestFace;
Now, go to your publish settings, and make it so only Flash (swf) and SWC are checked.
Publish this new project (you now have a swf/swc you can use as a RSL for other applications).
2. Setup your other applications to use the swf/swc as a RSL.
In your existing flash project, go to the 'Advanced Actionscript Settings' (click the wrench icon next "Actionscript 3.0" in the publish settings).
Click the library path tab, click the plus button, then click the "Browse To SWC File" button (currently it's an icon with the flash 'f' in it). Find your swc file from the previous step.
Now, with your new entry highlighted, click the info icon (linkage options). Change it from "Merged into code" to "RSL". Then add a path to the swf file (where it will be when this application runs).
Now, in your application, you can reference classes from the RSL. So if we do this:
trace(TestyMcTestFace.go());
You should get the output "I'm Testy McTestFace".
FlashPro will automatically load the RSL for you. Be aware though, that if you aren't letting flash preload your app automatically, it won't be available right away.
If you changed and re-exported the swc/swf from step one, those changes should be reflected when you run your existing swf again (no recompiling necessary).
Caveats:
Be careful with code in RSL's. It's easy to get clashing classes. As a best practice, only put code that is completely standalone/de-coupled into RSL's. Code that has lots of imports should be avoided. It's also best if you don't reference classes with same names in your compiled swf's that you are loading the RSL's.
Also keep in mind that RSL's can have sanbox/security restrictions if not coming from the same domain.
not possible, RSL is only meant for runtime sharing not for compile time sharing which you need to access the class.
First thing is, one class is not that much in term of size so there's not really a need to make it unique a sharable between swfs.
Now you affirm that all swfs would have to be recompiled if you make any change but that's not actually accurate since only one class definition can exist in one given runtime. The first swf running is by default the one loading the class definition, all the loaded swfs following would have their class definition discarded by default so no you don't have to recompile them in theory.
So to resume yes you have to recompile all swfs if you make major changes to the class but not for minor changes. But that situation is symptomatic to your app design which might not be the most efficient and logical.

What is the initial class in a new Flash Builder project supposed to represent?

I'm learning Flash Builder so I can add some extra functionality to my Flash Pro project.
Let's say I create a new Flash Pro file called foo.fla. I can then open Flash Builder and create a new project (and in the setup wizard I specify my foo.fla file as the target of the project). The wizard then creates a new project containing one file called foo.as which extends Sprite.
Now I would expect this initial file to be a root of some kind, and a great central place where I could create variables that all my MovieClips need to share. However, I can't figure out what exactly this file is being used for when my project is run. It doesn't seem to correspond to the stage or to the parent of any of my movie clips. It's constructor doesn't even seem to be called. What is this file used for? Is there a way I can use it to store 'global' stuff?
In order to "link" it to your FLA, you'll want to set it as the document class:
Once you do that, the constructor should be called at startup.
This class is exactly what you think it is: root*.
The class that you provide is the class that is associated with your .fla file.
It is called the document class or main class.
You are probably familiar with the concept of associating a library symbol with a class.
Say you create a MovieClip, add it to your library and define a class for it.
This is pretty much the same thing now, except you add the class to the document.
When the flash player executes your .swf file, it will instantiate your class and add it to the display list. This has a couple of implications:
The class must be some DisplayObject, because it is added to a DisplayObjectContainer.
This is why you it extends Sprite. (Sprite is a lightweight class that you should prefer over MovieClip if you do not need a timeline)
This is the strange part, remember * up there?
Yes, as your swf is created, the document class is instantiated and the resulting object is added to the display list, this means that root isn't actually the root of the display hierarchy. There's a parent container and that is stage.
Think of root as the root of your application, not necessarily the top most root of all roots.
And here's the (imo) strangest thing:
You can access the stage property within the constructor of the document class.
This is not true for any other class that extends DisplayObject (unless you force it by passing stage as a parameter to the constructor, which you shouldn't be doing)) and who's objects will end up on the display list, because you have to addChild them after they are created.
You might be tempted to use the stage property in such a constructor that is a constructor of a document class (because you can), but this leads to problems, because you can never tell if your document class is actually used as a document class.
If you want to instantiate your current document class in some other project, it will not have the special status of being the document class. It will be some regular class as all the others of that project.
In this case, stage will be null in the constructor. So don't access stage in the constructor, even if you can.
If you need stage, wait for it to be available. That is when the ADDED_TO_STAGE Event fires.

Package flash game to AIR mobile (IPA)

I have a complicated game project using multiple libraries, swc, assets, etc. The output is a two swf files (shell with the menu and the game itself). Packing in IPA (iOS) does not work immediately because of a lot of problems and settings ANT. But build as swfs work fine.
Is it possible to create a separate mobile as3 project, which will load the first swf to full screen, which will load the second swf, and then build it? How best to do this? Or are there other options?
Try this:
Compile a copy of your main game swf as an swc.
In a copy of your menu swf, point it to the game swc and in the place you would normally go through the motions of loading the external game swf, just directly add a new instance of the root game class:
// Before:
var ldr:Loader = new Loader();
... other stuff, progress monitoring, etc. ...
var mcGame:MovieClip = ldr.content as MovieClip;
// After - one line:
import my.game.namespace;
var mcGame:GameClass = new GameClass();
Compile this updated menu project as a swc.
In your mobile app, add an instance of the root class of the menu stage:
// Constructor for root class of mobile app
public function AppRoot() {
this.addChild(new GameMenu());
}
Now everything is bundled in a single compiled project.

Accessing variables inside embedded SWF?

I'm programming an AS3 application which loads an external SWF file to a movie clip in my stage. I need to read a variable inside the embedded SWF. I think I can, probably, do this through the bgURL, but I can't figure out how.
How can I read a variable inside the embedded SWF?
var bgLoader:Loader = new Loader();
var bgURL:URLRequest = new URLRequest("file.swf");
bgLoader.load(bgURL);
addChild(bgLoader);
That would be something like trace(MovieClip(bgLoader.content).Player.played);, but make sure you access the content in the Event.COMPLETE handler:
bgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,bgLoaded);
function bgLoaded(event:Event):void{ trace(MovieClip(bgLoader.content).Player.played) }
bgLoader.content returns a DisplayObject, but you need to access you content as a MovieClip. To do so you use casting.
This is presuming your external swf is also AS3 (good point Teo.sk !)
This bit: _root.Player.played looks like AS2. Unfortunately you can't access
variables form a loaded AS2 movie directly.
Still, you can use Local Connection class to send variables back and forth betwen
AS2 and AS3. Luckily Grant Skinner wrote a nice little utility called SWFBridge
to make this easier

flash cs5: compiling fla with huge internal library takes YEARS !

by using flash cs5 with a huge internal image library (over 300+ small png-files) i need more than 90seconds for each compiling action! the as code is pretty well, also my computer (quad core, 4gigs of ram). i've found out, that by exporting the files to "stage 1" (bild 1 in my screenshot) flash starts to hang around, but i don't know why...
.
how to speed this process up ?
__________________________________________________________________________________________________________________________________________
__________________________________________________________________________________________________________________________________________
my solution did not work:
so i've played around and ended up creating *.as-files for each single bitmap, but the speed-result is the same (maybe 10% - 15% faster than before)...
package
{
import flash.display.*;
dynamic public class MY_BITMAP_NAME extends BitmapData
{
public function MY_BITMAP_NAME(width:int = 500, height:int = 135)
{
super(width, height);
return;
}
}
}
i can not work fast enough to debug my project files :-(
The solution would be to move your assets inside a precompiled SWC library that you will only recompile when they change.
Building the library:
create a new FLA and move in your Bitmaps,
each image needs to have a linkage class name and be exported in first frame; you don't have to create an AS class, Flash will generate them,
in the publish settings, "Flash" tab, check "Export SWC",
this SWC library will be published in the same location as the SWF; in CS4-5 you can't prevent the SWF creation.
Using the library
in your main FLA publish settings, "Flash" tab, open the Advanced Actionscript 3 settings dialog,
in the "Library path" tab you can add the assets library SWC; make sure the "Link Type" is "Merged into code",
SWC content will be available in your main FLA as if they were in the library.
It is worth noting that:
you must instantiate these assets by code (ie. new AssetName): they will not appear in your main FLA's Library panel and you can not drop them on the timeline,
only assets you explicitly reference in your code will be available at run time; if you are using getDefinitionByName() you must still import the assets somewhere in your code. For instance you can declare an Array containing all your assets classes (ex: var assets:Array = [AssetClass1, AssetClass2,...]).
if these 300+ images don't change too often, you could create a second .fla, where you only put the images in the library. Then you publish that .fla as a swc file (You can set this in the publish settings).
And you use that swc in your original .fla (that now has no images anymore), where you have your code (using the swc means, in the publish settings -> actionscript settings, you set the swc as a library reference).
This way, Flash only has to compile your code and simply takes the already compiled images from the swc. It then should compile much faster.
ctrl+enter, that will compile all things in library and the AS code.
most situation that use just change little things, and then compile it.
it would waste much time that no need to waste.
you can export some thing that would not always be changed to SWC file, and to to publish setting,
add SWC file into your Fla. or move you Fla project to Flash build, compile use less time more than in flash ide.