2

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.
Demian Brecht
  • 21,135
  • 5
  • 42
  • 46
  • When error is thrown , right after run or even after load external SWF ? – turbosqel Jan 17 '12 at 06:58
  • In this example, it's thrown on instantiation of the class. – Demian Brecht Jan 17 '12 at 07:07
  • So , You load external SWF to wrong application domain if main app cannot access it . How You loading liba.swf , You use LoaderContext ? – turbosqel Jan 17 '12 at 07:59
  • @turbosqel: No, no `LoaderContext`. In this context (no pun intended ;)), I don't believe it makes a difference as this is not web based. It's essentially running locally from Flash Player (3rd party VM implementation). – Demian Brecht Jan 17 '12 at 09:33
  • @turbosqel: I should add, however, that I tried using the `LoaderContext` and it didn't make a difference (perhaps I did something wrong though). – Demian Brecht Jan 17 '12 at 09:34
  • 2
    try to load with 'new LoaderContext(false ,ApplicationDomain.currentDomain);' , it may help . – turbosqel Jan 17 '12 at 09:40
  • @turbosqel: Please add your comment as an answer to be accepted. It fixed my issue. Apparently I was constructing the `LoaderContext` incorrectly when I tried it last. Thanks. – Demian Brecht Jan 18 '12 at 19:15

2 Answers2

2

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.

divillysausages
  • 7,883
  • 3
  • 25
  • 39
  • Your assumption is correct and that's what's being done (linkage is set to external and I'm manually loading the swf containing the class definition). Funny thing is, this works as expected in the third party runtime that I'm using, but not in Flash. My full use case is actually a little more complex, introducing inheritance that's defined cross-swc (i.e. `LibB` extends `LibA`). – Demian Brecht Jan 17 '12 at 00:48
  • see new edit - it's working on my end. Also, props to @turbosqel – divillysausages Jan 17 '12 at 10:12
  • Yes, that fixed it for me. If @turbosqel doesn't add an answer (as he did suggest the fix first), I'll accept this one - thanks for the help. – Demian Brecht Jan 18 '12 at 19:16
  • i expect that this will be a problem , because You need to load Classes to same application domain if You need classes in cross-swf. When You load swf that read classes from parent , it can be a child domain . For more info read about RSL stuff . – turbosqel Jan 19 '12 at 08:17
0

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

The_asMan
  • 6,364
  • 4
  • 23
  • 34
  • It doesn't actually *have* to be there at compile time using swc definitions. – Demian Brecht Jan 17 '12 at 01:35
  • If you try to instantiate a class the class needs to be imported. That is exactly why you are getting VerifyError: Error #1014: Class LibA could not be found. And just like turbosqel suggested use LoaderContext. – The_asMan Jan 17 '12 at 16:07