A tutorial by Aral Balkan
Charles Iliya Krempeaux asked a question on the MTASC list on how to create and use dynamically linked libraries in Flash.
When you write software in another language, you can create "libraries". For example, if I were writing code in C#, then I could create .dll files (which would contain classes, etc that I could use in other programs). Is there a way to do this with ActionScript?
You can create DLLs in Flash – in fact, a DLL is nothing more than a regular SWF that only contains classes.
The process is simple:
Download the source and example: dll_loader.zip (25kb)
SWF DLL Test)library) and one for your application (application). The application will load in and use the DLL.dll.fla)import com.ariaware.tests.dll.library.*;
FirstClass and SecondClass, which you've placed in the com.ariaware.tests.dll.library package. Merely importing them is not enough to have them compiled into your DLL SWF, you must actually reference them so add the following code to the first frame of your FLA:// Reference the classes so that they get compiled into the DLL
FirstClass;
SecondClass;
class com.ariaware.tests.dll.library.FirstClass { function FirstClass() { trace ("FirstClass constructor"); } function aMethod() { trace ("FirstClass.aMethod()"); } }
class com.ariaware.tests.dll.library.SecondClass { function SecondClass() { trace ("SecondClass constructor"); } function aMethod() { trace ("SecondClass.aMethod()"); } }
dll.swf in your /library folder.application folder, create a new FLA called application.flacom.ariaware.tests.dll.Application. Here is the code for the Application class:import com.ariaware.tests.dll.library.*; import com.ariaware.arp.utils.dll.DLLLoader; import com.ariaware.arp.utils.dll.DLLEvent; import mx.utils.Delegate; class com.ariaware.tests.dll.Application extends MovieClip { // On stage var dllLoader:DLLLoader; var txtPreloader:TextField; // Event listener delegates var progressDelegate:Function; var completeDelegate:Function; private function onLoad() { // Create delegates so we have method closures progressDelegate = Delegate.create ( this, dllProgress ); completeDelegate = Delegate.create ( this, dllComplete ); // Listen for preloader events on loader dllLoader.addEventListener ( "progress", progressDelegate ); dllLoader.addEventListener ( "complete", completeDelegate ); // Load the DLL dllLoader.loadDll ( "../library/dll.swf" ); } // // Event handlers // // Called on DLL load progress private function dllProgress ( evt:DLLEvent ) { var bytesLoaded:Number = evt.bytesLoaded; if ( bytesLoaded <= 100 ) { txtPreloader.text = "Waiting to load..."; } else { txtPreloader.text = Math.round ( evt.bytesLoaded * 100 / evt.bytesTotal ) + "% loaded."; } } // Called when the DLL has completely loaded private function dllComplete ( evt:DLLEvent ) { // Remove preloader event listeners dllLoader.removeEventListener ( progressDelegate ); dllLoader.removeEventListener ( completeDelegate ); // Display status message txtPreloader.text = "DLL Loaded!"; // // Test the library classes // var firstClass:FirstClass = new FirstClass(); firstClass.aMethod(); var secondClass:SecondClass = new SecondClass(); secondClass.aMethod(); } }
dllComplete event handler gets called. Here you refer to FirstClass and SecondClass but, when you compile Application.fla you don't want to add these classes to your SWF (this would really defeat the purpose of using a DLL!) But if you don't load in the classes, the Flash compiler will give you an error. What to do? Intrinsic classes to the rescue. If you create intrinsic classes for each class that you will use from your library, you won't get any compile-time errors and you'll benefit from compile time type-checking on linked classes. Here is the code for the intrinsic FirstClass class: intrinsic class com.ariaware.tests.dll.library.FirstClass { public function aMethod():Void; }
SecondClass class is almost identical. Notice how the fully-qualified class name for the intrinsic classes is identical to the fully-qualified class name of the actual classes in the Library.intrinsic class com.ariaware.tests.dll.library.SecondClass { public function aMethod():Void; }
DLLLoader and link it to the class com.ariaware.arp.utils.dll.DLLLoader. Here is the code for the DLLLoader class:import mx.events.EventDispatcher; import com.ariaware.arp.utils.dll.DLLEvent; class com.ariaware.arp.utils.dll.DLLLoader extends MovieClip { // On Stage var deadPreview:TextField; // Dynamically created clips var loaderShell:MovieClip = null; // // Group: Events broadcast // // Event: progress - On load progress (every frame) // Event: complete - When DLL has completely loaded // public function DLLLoader () { EventDispatcher.initialize ( this ); } //////////////////////////////////////////////////////////////////////////// // // Method: loadDll() // // Starts loading the specified DLL (SWF) file. A valid DLL file is a // SWF file that contains AS2 classes. // //////////////////////////////////////////////////////////////////////////// public function loadDll ( dll:String ) { // Create shell movie clip to load DLL into if it doesn't already exist if ( loaderShell == null ) { loaderShell = createEmptyMovieClip ( "loaderShell", getNextHighestDepth()); } // Load the movie loaderShell.loadMovie ( dll ); // Start the preloader onEnterFrame = preloader; } //////////////////////////////////////////////////////////////////////////// // // Group: Private methods // //////////////////////////////////////////////////////////////////////////// private function onLoad () { deadPreview._visible = false; } // Preloader method called every frame after DLL starts loading private function preloader () { var bytesLoaded:Number = getBytesLoaded(); var bytesTotal:Number = getBytesTotal(); if ( bytesLoaded == bytesTotal && bytesLoaded > 10 ) { // Ok, DLL has loaded -- wait a frame for it // to initialize so the classes become available. onEnterFrame = waitForInit; } else { dispatchEvent ( new DLLEvent ( "progress", bytesLoaded, bytesTotal ) ); } } // DLL has initialized. Broadcast the complete event private function waitForInit () { onEnterFrame = null; dispatchEvent ( new DLLEvent ( "complete", getBytesLoaded(), getBytesTotal() ) ); } // // Note: Methods to be mixed in by the EventDispatcher // function addEventListener(){}; function removeEventListener(){}; function dispatchEvent(){}; }
class com.ariaware.arp.utils.dll.DLLEvent { var type:String; var target:Object; var bytesLoaded:Number; var bytesTotal:Number; function DLLEvent ( type, bytesLoaded, bytesTotal ) { this.type = type; this.bytesLoaded = bytesLoaded; this.bytesTotal = bytesTotal; } }
txtPreloader.DLLLoader movie clip symbol into your Application symbol (form).Note: Unless otherwise stated, all code is released under the MIT license (I've removed some comments, license notes, etc. from the code to make it easier to read online.) Full license information can be found in the source download.
I will be adding the DLLLoader and DLLEvent classes to the experimental branch of ARP.
Download the source and example: dll_loader.zip (25kb)
In response to the tutorial, Clément Arnoux wrote the following on OSFlash mailing list:
First of all, why for such a simple example didn't you talk about the exclusion xml as a possible solution along with intrinsic classes?
Clément's right: Using an exclude.xml file here (instead of intrinsic classes) is a viable alternative. It means that you can include the actual library in your classpath but, using the exclude.xml file, tell Flash to not include the library classes in your final SWF. It will offer you all the same advantages as using an intrinsic file (such as compile-time type checking), along with a couple of extras (the most important being that you won't have to update the interfaces of your intrinsic classes whenever your actual class interfaces change.)
The only difference between the intrinsic class and exclude.xml methods is the following:
Instead of creating intrinsic classes for each class in your library, you create a single exclude.xml file and name it nameOfYourFLA_exclude.xml. Here is the listing of the exclude XML file for this example:
<excludeAssets> <asset name="com.ariaware.tests.dll.library.FirstClass" /> <asset name="com.ariaware.tests.dll.library.SecondClass" /> </excludeAssets>
Download the source and example: dll_loader_exclude_xml.zip (23kb)
Discussion