Actionscript 3 - Script Libraries

542 views Asked by At

I'm attempting to load the resulting swf of a swc build manually. Due to my particular environment, we have a need to segregate class definitions into swcs (where it makes sense) to remove redundant code from output swfs.

In a nutshell, I'm defining a class (LibA) in a swf that I'm building with compc. I'm compiling it both into swc and directory formats so I can easily extract library.swf from the directory to load at runtime (external linkage) and use the swc to compile out from any swf's built either with Flash CS5 or mxmlc.

LibA.as:

package
{
    public class LibA
    {
        public function LibA()
        {
            trace("*** LibA()");
        }
    }
}

Main.as:

package
{
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;

    public class Main extends Sprite
    {
        private var self:Main;
        private var context:LoaderContext;

        public function Main()
        {
            var l:Loader = new Loader();
            self = this;

            l.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event) {
                self.addChild(l.content);

                var liba:LibA = new LibA();
            });
            l.load(new URLRequest("./libs/build/liba.swf"));
        }
    }
}

I build the swc/directory swc with

compc -output libs/build/liba.swc -include-sources libs/LibA.as -debug=true

and I set the appropriate linkage in AS3 settings in Flash CS5 when building Main (class linked directly to the stage).

Everything publishes without an issue.

However, at runtime I get VerifyError: Error #1014: Class LibA could not be found.

What am I missing here? I want to be able to load and use classes defined within liba.swf from my Main.swf.

Full trace dump:

verify Function/<anonymous>()
                        stack:
                        scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ Main$ Main Main] 
                         locals: Object flash.events::Event? * 
  0:getlex 4
                        stack: Main?
                        scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ Main$ Main Main] 
                         locals: Object flash.events::Event? * 
  2:getlex 7
                        stack: Main? flash.display::Loader?
                        scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ Main$ Main Main] 
                         locals: Object flash.events::Event? * 
  4:getproperty content
                        stack: Main? flash.display::DisplayObject?
                        scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ Main$ Main Main] 
                         locals: Object flash.events::Event? * 
  6:callpropvoid addChild 1
                        stack:
                        scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ Main$ Main Main] 
                         locals: Object flash.events::Event? * 
  9:findpropstrict LibA
                        stack: Object
                        scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ Main$ Main Main] 
                         locals: Object flash.events::Event? * 
  11:constructprop 10 0
                        stack: *
                        scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ Main$ Main Main] 
                         locals: Object flash.events::Event? * 
  14:coerce LibA
VerifyError: Error #1014: Class LibA could not be found.
2

There are 2 answers

4
divillysausages On BEST ANSWER

If you want to load classes from a SWF, you'll need to do something like (in your event handler):

var li:LoaderInfo = e.target as LoaderInfo; // get the loaderInfo object from the event
var swf:MovieClip = li.loader.content as MovieClip; // get the swf
var c:Class = swf.loaderInfo.applicationDomain.getDefinition( "LibA" ) as Class; // get the class definition for LibA

Creating a new c should give you your LibA object. You'll need the full class definition as a name.

If I understand what you're trying to do though, I'm pretty sure you can set the SWC to embed an an external library - that is you get code completion, but none of the classes are included, and the SWC is searched for at runtime.

EDIT

Just tried something like what you're doing. In my example above, when you create c, if you trace it out, it'll trace LibA. However, if you explicitly reference it, you'll get the error that you describe. I think this is because Flash is getting confused with essentially 2 definitions of LibA - the one that was referenced and the one you're loading - they're in 2 different application domains.

The fix is as @turbosqel describes it, load it in with a LoaderContext object:

var l:Loader = new Loader();
var context:LoaderContext = new LoaderContext( false, ApplicationDomain.currentDomain );
l.contentLoaderInfo.addEventListener(Event.COMPLETE, this._onLoadComplete );
l.load(new URLRequest("./libs/build/liba.swf"), context);

This works for me, I can now explicitly reference the LibA class.

2
The_asMan On

liba does not exist until your SWF is loaded because you are not importing it into main.

Which means at compile time it is not there

Move var liba:LibA = new LibA(); into a function call on the loaded swf root and call the function after load e.currentTarget.someFunc