【问题标题】:AS3 Air Desktop - Dispatch Custom Event from SWF in ApplicationStorageDirectoryAS3 Air Desktop - 从 ApplicationStorageDirectory 中的 SWF 调度自定义事件
【发布时间】:2017-06-02 15:55:53
【问题描述】:

我创建了一系列 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 上的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);
}

回答 请参阅下面的@BadFeelingAboutThis 答案以了解发生 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 文件。

【问题讨论】:

  • 您是否在主机 swf 和 dashboard.swf 中都引用了该类 (CustomEvent)?很可能是的,因为根路径不同,安全沙箱也不同,并且您有两个冲突的类,它们实际上是相同的,但并不被视为相同
  • @BadFeelingAboutThis - 我愿意。从 ApplicationDirectory 加载 dashboard.swf 时,它工作正常。当它从 ApplicationStorageDirectory 加载时,我遇到了这个问题。所以实际的代码有效。它与文件的位置有关,我不知道为什么。
  • 尝试将您的加载器上下文设置为currentDomain,就像这里的最后一个示例:help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/…
  • 您应该添加您的实际解决方案作为答案,然后接受它。这有助于未来的访问者快速获得最相关的信息。

标签: actionscript-3 flash air


【解决方案1】:

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

在您的情况下,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

【讨论】:

  • 感谢您的精彩解释!但是,现在我遇到了这个问题:SecurityError: Error #2142: Security sandbox violation: local SWF files cannot use the LoaderContext.securityDomain property
  • 如果我删除 context.securityDomain,我又回到了原点。我尝试从服务器下载 swf,将它作为 ByeArray 保存在 ApplicationStorageDirectory 中,然后从那里与上下文一起加载它。没运气。然后我尝试直接从服务器加载它并遇到了同样的问题。
  • 删除安全域行时是否要离开应用程序域?那可能会奏效。所以像这样:loader.load(yourUrlRequest, new LoaderContext(false,ApplicationDomain.currentDomain)); 还是你已经尝试过的?
  • 是的。我已经这样做了(请参阅我在您最后一个评论上方的评论)。我一直在到处寻找,找不到一个可靠的答案来解释为什么这不起作用。 ApplicationDomain 绝对是正确的方法,但它只是行不通。
  • 尝试将 false 作为 LoaderContext 构造函数中的第一个参数传递,这将不会检查策略文件,因为没有策略文件可以在本地加载,这可能会导致问题。尝试使用我之前评论中的行。
猜你喜欢
  • 2011-11-12
  • 1970-01-01
  • 2015-01-10
  • 1970-01-01
  • 2011-09-19
  • 1970-01-01
  • 1970-01-01
  • 2012-03-09
  • 1970-01-01
相关资源
最近更新 更多