views:

774

answers:

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");
 }

. . . }

A: 

@ 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
A: 

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