在Flex中创建插件 - 加载嵌套的SWF文件

时间:2022-11-02 21:19:00

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.

我正在尝试为我们的应用程序实现一个插件系统,并且有一段时间获得自动动态加载的SWF文件,加载其他SWF文件。

It goes something like this:

它是这样的:

  1. Main Application Shell loads...
  2. 主要应用Shell加载......

  3. ---------+ Application loads...
  4. --------- +应用程序加载......

  5. -----------------+Plugin(s)

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

我没有问题让app#1加载app#2

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

但是,尽我所能,我无法获得app#2来加载和实例化#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.

我已经使用ModuleManager尝试了各种排列,但这是我得到的最接近的排列。调用onLoadComplete方法时,我可以看到SWF已加载,但工厂始终返回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.

有趣的是,当我在自己的应用程序中提取它时,它工作正常。这个问题是由我从一个动态加载的SWF加载插件这一事实引发的。

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.

我相信这是由于ApplicationDomain,但我无法做出正面或反面。我尝试指定currentDomain,new ApplicationDomain(Application.currentDomain)和new ApplicationDomain()但没有成功。

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.

此外,重要的是要注意,我不能在任何一个应用程序中引用Foo类的硬引用,因为从它们的性质来看,我们不会提前知道它们将包含什么。

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

Googlin',这似乎是一个相当已知的问题,但我还没有找到(明确的)解决方案。

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

2 个解决方案

#1


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

@joshtynjala是对的。我发现尝试只使用Object然后调用它的方法(不要强制转换)。

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

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 ?

一般可以在系统/ flex类之间转换没问题。不知道将Plugin作为运行时库放置会有所帮助吗?

#2


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.

如果您真的想在插件和应用程序之间使用通用接口,那么您的应用程序的插件类必须与插件的插件类相同。为此,他们需要b在同一个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 :

问题是,当你编译你的插件swf时,你也会编译插件。这不是问题,但您需要告诉您的应用程序它与他的相同:

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 :

ApplicationDomain.currentDomain是这里的关键。如果您参考文档:

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.

Loader自己的ApplicationDomain。使用ApplicationDomain.currentDomain时使用此应用程序域。加载完成后,父级和子级可以直接使用彼此的类。如果子项尝试定义与父项已定义的类名相同的类,则使用父类,并忽略子类。

#1


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

@joshtynjala是对的。我发现尝试只使用Object然后调用它的方法(不要强制转换)。

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

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 ?

一般可以在系统/ flex类之间转换没问题。不知道将Plugin作为运行时库放置会有所帮助吗?

#2


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.

如果您真的想在插件和应用程序之间使用通用接口,那么您的应用程序的插件类必须与插件的插件类相同。为此,他们需要b在同一个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 :

问题是,当你编译你的插件swf时,你也会编译插件。这不是问题,但您需要告诉您的应用程序它与他的相同:

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 :

ApplicationDomain.currentDomain是这里的关键。如果您参考文档:

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.

Loader自己的ApplicationDomain。使用ApplicationDomain.currentDomain时使用此应用程序域。加载完成后,父级和子级可以直接使用彼此的类。如果子项尝试定义与父项已定义的类名相同的类,则使用父类,并忽略子类。