2

I'm trying to implement a plugin system for our application, and having a devil of a time getting SWF file which was dynamically loaded itself, load additional SWF files.

It goes something like this:

  1. Main Application Shell loads...
  2. ---------+ Application loads...
  3. -----------------+Plugin(s)

I have no problem getting app #1 to load app #2

However, try as I might, I cannot get app #2 to load and instantiate #3

I've tried various permutations using the ModuleManager, but this is the closest I get. When the onLoadComplete method get invoked, I can see that the SWF loaded, however the factory always returns NULL.

What is interesting is that when I extract this out in its own application, it works fine. This issue is triggered by the fact that I'm loading Plugin from a SWF that was loaded dynamically itself.

I believe this is due to the ApplicationDomain, but I cannot make heads or tails of it. I tried specifying currentDomain, new ApplicationDomain(Application.currentDomain) and new ApplicationDomain() without success.

Also, it is important to note that I cannot make reference a hard reference to the Foo class in either applications since by their nature, we will not know ahead of time what they will contain.

Googlin' around, this seems to be a fairly known problem, but I have not found a (clear) solution yet.

.
.
.
assetModule = ModuleManager.getModule("Foo.swf");    
assetModule.addEventListener(ModuleEvent.READY, onLoadComplete );
assetModule.addEventListener(ModuleEvent.ERROR, onLoadError);
assetModule.load();
.
.
.
private var _pluginInstance:Plugin;

private function onLoadComplete( event:Event ):void
{
    trace("module loaded");

    _pluginInstance = assetModule.factory.create() as Plugin;
    if( _pluginInstance )
        _pluginInstance.startup();
    else 
        Alert.show("unable to instantiate module");
}

private function onLoadError( event:Event ):void
{
       Alert.show("error");
}

My Plugin looks like this:

package
{
    import mx.collections.ArrayCollection;
    import mx.modules.ModuleBase;

        public class Plugin extends ModuleBase

        public function startup():void
        {

        }
.
.
.
}

and

package 
{
    import Plugin;
    import mx.modules.ModuleBase;

    public class Foo extends Plugin
    {
        public function Foo()
        {
            trace("foo constructor invoked");
        }

        override public function startup():void
        {
                    trace("foo started");
        }
.
.
.
}
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Phil
  • 851
  • 6
  • 9
  • 1
    I haven't worked with application domains in a long time, so I can't provide an complete answer to your question, but I can tell you that the problem is happening here: assetModule.factory.create() as Plugin; The Plugin class in your module and the Plugin class in your main app are not the same, as far as the VM is concerned. Casting with "as Plugin" returns null because Plugin != Plugin. How to work around that (other than casting it as Object or something), I can't remember, but you're on the right track investigating the ApplicationDomain class. – Josh Tynjala Apr 29 '09 at 22:15

2 Answers2

0

If you really want to use a common interface between your plugin and your application, your application's Plugin class must be the same as your plugin's Plugin class. To do so, they need b to be in the same ApplicationDomain.

//In an external library
public interface Plugin {}

//In your application
_pluginInstance = assetModule.factory.create() as Plugin;
...


//In your plugin
public class MyPlugin implements Plugin

The problem is, when you will compile your plugin swf, you will also compile Plugin. This is not a problem, but you need to tell your application that it's the same as his :

var loader:Loader = new Loader();
loader.addEventListener(Event.COMPLETE, onLoadComplete);
loader.load(new URLRequest("plugin.swf"), new LoaderContext(false, ApplicationDomain.currentDomain));    

ApplicationDomain.currentDomain is the key here. If you refer to the docs :

Loader's own ApplicationDomain. You use this application domain when using ApplicationDomain.currentDomain. When the load is complete, parent and child can use each other's classes directly. If the child attempts to define a class with the same name as a class already defined by the parent, the parent class is used and the child class is ignored.

subb
  • 1,578
  • 1
  • 15
  • 27
0

@ joshtynjala is right. I found try just using Object then calling methods on it (don't cast).

var MyPlugin : Object = getPlugin(); MyPlugin.doPluginFunc();

Generally can cast between system/flex classes no problem. Don't know if putting Plugin as a runtime library would help ?

nso1
  • 595
  • 9
  • 18