AS3 Air Desktop - 从ApplicationStorageDirectory中的SWF发送自定义事件

时间:2017-06-02 15:55:53

标签: actionscript-3 flash air

我创建了一系列Air Desktop游戏。在玩游戏之前,用户必须首先登录。为了简化操作,我在一个单独的项目中创建了登录系统,并将其保存为名为" dashboard.swf"的swf文件。打开游戏时,它会加载dashboard.swf并显示登录屏幕。除了登录功能之外,dashboard.swf还处理了许多其他内容,例如游戏中的常见设置。

每次我对dashboard.swf进行更改时,我都不想重新编译每个游戏。所以,我从服务器下载它。我最初在ApplicationDirectory中下载,保存和加载dashboard.swf,它在Mac上运行良好。在Window 10上进行测试并进行一些研究之后,我发现非OSX机器的ApplicationDirectory是只读的。

因此,我将dashboard.swf的位置更改为ApplicationStorageDirectory。当我在我的Mac上运行它时,swf加载得很好,但是第一个被调度的自定义事件抛出并出错:

TypeError: Error #1034: Type Coercion failed: cannot convert com.thisapp.event::CustomEvent@12786a9fed31 to com.thisapp.event.CustomEvent

两个CustomEvent.as文件都是相同的。当dashboard.swf保存到Mac并从Mac上的ApplicationDirectory加载时,它会正常启动。一旦我将它移动到ApplicationStorageDirectory,我就会收到此错误。所以我知道这不是实际自定义调度程序的问题。冒泡是真的,因此在可取消。

在这种情况下会导致类型强制失败的原因是什么?

这是我的自定义调度员:

public class CustomEvent extends Event {

    public static const GOT_RESULT: String = "gotResult";
    public var result: Object;

    public function CustomEvent(type: String, result: Object = null, bubbles: Boolean = false, cancelable: Boolean = false) {
        // constructor code
        super(type, bubbles, cancelable);
        this.result = result;
    }

    public override function clone(): Event {
        return new CustomEvent(type, result, bubbles, cancelable);
    }

}

从我的dashboard.swf:

dispatchEvent(new CustomEvent(CustomEvent.GOT_RESULT, null,true,true));

在桌面应用程序的主类中:

var dashboardURL:String = File.applicationStorageDirectory.url +"dashboard.swf";

  var myContext:LoaderContext = new LoaderContext(); 
myContext.applicationDomain = ApplicationDomain.currentDomain; 
var urlReq:URLRequest = new URLRequest(dashboardURL); 
var ldr:Loader = new Loader();
ldr.load(urlReq, myContext); 
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,loadit);
    function loadit(e:Event){
dashboard = e.target.content as MovieClip;
addChild(dashboard);
dashboard.addEventListener(CustomEvent.GOT_RESULT, runLogin);
}

ANSWER 请参阅下面的@ BadFeelingAbout这个答案,以了解1034错误发生的原因。以下是我修复它的方法:

首先 - 从服务器下载swf(我使用GreenSock' LoaderMax):

private function dowloadDashboard(){
    var url:String  = "https://path/to/your/swf/on/the/server.swf";
    var queue:LoaderMax = new LoaderMax({name:"mainQueue",onComplete:completeHandler});
    //Note: the format is set to "binary"
    queue.append( new DataLoader(url, {name:"mySwf",format:"binary", estimatedBytes:3000}) );
    queue.load();

    function completeHandler(event:LoaderEvent):void {
    //Note: "mySwf" is the name I gave to the DataLoader above.
         var b:ByteArray = LoaderMax.getContent("mySwf");
    //loadDashboard() is the next function and I'm passing the ByteArray to it.
        loadDashboard(b);
    }
                }

下一步 - 使用ByteArray加载带有正确上下文的swf:

private function loadDashboard(b:ByteArray) {
var myContext:LoaderContext = new LoaderContext();
        myContext.allowLoadBytesCodeExecution = true;
        myContext.allowCodeImport = true;
        myContext.applicationDomain = ApplicationDomain.currentDomain; 
var ldr:Loader = new Loader();
ldr.loadBytes(b,myContext);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,loadDone);
}

最后 - 将你的swf添加到舞台:

        function loadit(e:Event){
            dashboard = e.target.content as MovieClip;
            addChild(dashboard);
}

我希望能帮到别人!请记住,在我的情况下,我有一个Desktop Air应用程序正在下载并加载服务器上的swf文件。

1 个答案:

答案 0 :(得分:2)

此错误通常意味着您有来自不同来源的同一个类进入您的根应用程序。

在您的情况下,CustomEvent类必须存在于主机SWF文件中以及您在SWF文件中加载的文件中。

由于加载的SWF与主机SWF不在同一个应用程序域中,因此flash / AIR不会将重叠的类视为同一个类。因此,您在SWF中加载CustomEvent现在被视为com.thisapp.event::CustomEvent@12786a9fed31,它(尽管完全相同)被视为与com.thisapp.event:CustomEvent完全不同的类。由于您的代码引用了后者,因此当主机的CustomEvent尝试填入类型为:CustomEvent的对象引用时,它将抛出强制错误,因为它们实际上不是同一类。

通常,此问题的补救措施是为加载的SWF指定context,以便将加载的类集成到其自己的域中。这应该使用加载的SWF CustomEvent

覆盖主机CustomEvent
var ldr:Loader = new Loader();

//The second parameter for load takes a LoaderContext
ldr.load(new URLRequest(File.applicationStorageDirectory.url +"dashboard.swf"), new LoaderContext(false, ApplicationDomain.currentDomain)); 
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE,loadit);

function loadit(e:Event){
    dashboard = e.target.content as MovieClip;
    addChild(dashboard);
    dashboard.addEventListener(CustomEvent.GOT_RESULT, runLogin);
}

详细了解加载程序上下文herehere