2

I have a series of Air Desktop games that I created. Before the game can be played, the user must first log in. In order to streamline things, I created the login system in a separate project and saved it as a swf file called, "dashboard.swf". When the game is opened, it loads dashboard.swf and displays the login screen. In addition to the login functionality, dashboard.swf also handles a bunch of other stuff like common settings amongst the games.

I didn't want to recompile each game every time I made a change to the dashboard.swf. So, I have it download from a server. I was originally downloading, saving, and loading dashboard.swf in the ApplicationDirectory and it worked fine on Macs. After testing on Window 10 and doing some research, I found that ApplicationDirectory for non-OSX machines is read-only.

So, I changed the location of the dashboard.swf to the ApplicationStorageDirectory. When I run it on my Mac, the swf loads just fine, but the first custom event that gets dispatched throws and error:

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

Both CustomEvent.as files are identical. It fires just fine when dashboard.swf is saved to and loaded from the ApplicationDirectory on the Mac. Once I move it to ApplicationStorageDirectory, I get this error. So I know it's not an issue with the actual custom dispatcher. Bubbling is true and so in Cancellable.

What would be causing the Type Coercion failure in this situation?

Here's my custom dispatcher:

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

From my dashboard.swf:

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

In my Main class for the desktop app:

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 See @BadFeelingAboutThis's answer below to understand why the 1034 error is happening. Here's how I fixed it:

First - Download the swf from the server (I'm using the GreenSock's 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); } } 

Next - Load the swf with the proper context using the ByteArray:

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

Last - Add your swf to the stage:

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

I hope that helps somebody! Remember, in my situation, I have a Desktop Air app that is downloading and loading a swf file that lives on a server.

4
  • Do you have that class (CustomEvent) referenced in both the host swf and the dashboard.swf? Most likely yes and because the root paths are different the security sandbox is different and you have two clashing Class's that are actually the same but not seen as the same Commented Jun 2, 2017 at 16:03
  • @BadFeelingAboutThis - I do. It works fine when the dashboard.swf is loaded from the ApplicationDirectory. It's when it's loaded from the ApplicationStorageDirectory that I get this problem. So the actual code works. It has something to do with the location of the file and I can't figure out why. Commented Jun 2, 2017 at 16:07
  • Try setting your loader context to currentDomain like the last example here: help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/… Commented Jun 2, 2017 at 16:08
  • you should add your actual solution as an answer and then accept that. This helps future visitors get to the most relevant info quickly. Commented Jun 5, 2017 at 15:58

1 Answer 1

2

This error typically means that you have the same Class coming into your root application from different sources.

In your case CustomEvent class must exist in both the host SWF file as well as your loaded in SWF file.

Because your loaded SWF is not in the same application domain as the host SWF, flash/AIR will not see overlapping classes as the same class. So you loaded in SWF CustomEvent is now seen as com.thisapp.event::CustomEvent@12786a9fed31 which (though exactly the same) is seen as a totally different class than com.thisapp.event:CustomEvent. Since your code references the latter, anytime a CustomEvent from the host tries to get stuffed in an object reference typed :CustomEvent it will throw a coercion error because they aren't actually same class.

Usually, the remedy for this problem is to specify the context for the loaded SWF so it integrates the loaded Classes into it's own domain. This should overwrite the host CustomEvent with the loaded SWF's 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); } 

Read more about the loader context here and here

Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for the great explanation! However, now I'm running into this: SecurityError: Error #2142: Security sandbox violation: local SWF files cannot use the LoaderContext.securityDomain property
If I remove context.securityDomain, I'm back to square one. I've tried downloading the swf from the server, saving it as a ByeArray in the ApplicationStorageDirectory, then loading it from there with the context. No luck. Then I tried loading it directly from the server and got the same issue.
Are you leaving the application domain when you remove the security domain line? That will probably work. So something like this: loader.load(yourUrlRequest, new LoaderContext(false,ApplicationDomain.currentDomain)); or is that what you've already tried?
Yeah. I already did that (see my comment above your last one). I've been searching everywhere can can't find a solid answer on why this wouldn't be working. ApplicationDomain is absolutely the right way to go, but it's just not working.
Try passing false as the first argument in the LoaderContext constructor, this will NOT check for a policy file and since there is no policy file to load locally that could the issue. Try using the line in my previous comment.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.