I have two swf files hosted on different domains aaa.com/a.swf and bbb.com/b.swf. a.swf is loading b.swf and trying to cast it to some interface. When both of these swf files are under the same domain everything works fine. But when they are under different domains I'm getting null after casting b.swf to the implemented interface IComponent. Both of these swfs are compiled with use-network=true and with the same IComponent.as.
public class Wrapper extends Sprite
{
public function Wrapper()
{
super();
var request:URLRequest = new URLRequest("http://aaa.com/Component.swf");
var loaderContext:LoaderContext = new LoaderContext();
loaderContext.applicationDomain = ApplicationDomain.currentDomain;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoadingComplete);
loader.load(request,loaderContext);
addChild(loader);
}
private function onLoadingComplete(event:Event):void
{
var target:LoaderInfo = event.target as LoaderInfo;
var component:IComponent = target.content as IComponent;
component.init({"s":1});
component.run();
}
}
public class Component extends Sprite implements IComponent
{
public function Component()
{
super();
Security.allowInsecureDomain("*");
}
public function init(params:Object):void
{
//some actions
}
public function run():void
{
//some actions
}
}
Try this:
//Assuming you've set a crossdomain policy file
var loaderContext:LoaderContext =
new LoaderContext( true , ApplicationDomain.currentDomain )
It seems that the reason why it's not working has to do with the fact that either IComponent is not recognized or that there's a definition conflict. I would have thought that with ApplicationDomain set to currentDomain, a definition conflict should have been avoided... but it may be worth trying to leave each SWF within their own domain.
//Assuming you've set a crossdomain policy file
var loaderContext:LoaderContext =
new LoaderContext( true );
You could also check if IComponent "exists" before loading the other SWF. This could help in diagnosing what's going on...
var ClassName:Object = getDefinitionByName('IComponent');
trace( ClassName );
Maybe you have to set cross-domain security policy by crossdomain.xml file
http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security.html
For example:
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy
SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*.example.com" />
</cross-domain-policy>
Thanks all for answers, I've found a working solution today.
Instead of casting loaded content to IComponent I'm casting it to object
var component:Object = (event.target as LoaderInfo).content as Object;
component["init"](null);
component["run"]();
I's confimed from testing that even when we are using shared class with static fields and methods it doesn't work. Both of wrapper and component are instantiating their own instances of shared class. It's really strange.
If you have the same problems please ensure that your wrapper/component classes have Security.allowDomain calls
This is a bug in the player:
http://bugs.adobe.com/jira/browse/ASC-3529
It happens when you try to "share" an interface between swfs that were loaded from different domains. This should work provided that you put both swfs under the same app domain (as you have).
Using an Object works, but kind of defeats the purpose of using an interface in the first place.
Here's a workaround that basically loads the swf as a binary and then uses Loader::loadBytes to actually load the swf into memory:
http://blog.aleksandarandreev.com/?p=42
my idea about syntax errors was pointless, here's an edit:
this code:
private function ololo():void{
var request:URLRequest = new URLRequest("http://domain/file.swf");
var loaderContext:LoaderContext = new LoaderContext();
loaderContext.applicationDomain = ApplicationDomain.currentDomain;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoadingComplete);
loader.load(request,loaderContext);
}
private function onLoadingComplete(e:Event):void {
var target:LoaderInfo = e.target as LoaderInfo;
addChild(target.content as Sprite);
}
works well even if files are on completely different domains.
does it work if you treat your IComponent as Sprite?
Related
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.
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
I will try to write a sharedObject item using my swf embeded into an html page.
"allowscriptaccess" is setted to "never". I can't write sharedObject!
However if I set allowscriptaccess to "always", write action work well...
If I can't use sharedObject with allowscriptaccess setted to never, exist alternative for saving data?
I write a little and stupid example:
public class Main extends Sprite {
private var SHARED_NAME:String = "__SO__";
private var so:SharedObject;
Security.allowDomain("*");
Security.allowInsecureDomain("*");
public function Main() {
this.so = SharedObject.getLocal(this.SHARED_NAME, "/");
this.setSharedObj("YEAHHHHHHHH");
this.getSharedObj();
}
public function getSharedObj(clientId:String = null):Object {
var url:String = "http://localhost:8080?so=" + this.so.data.test;
var request:URLRequest = new URLRequest(url);
var loader:URLLoader = new URLLoader();
loader.load(request);
return this.so.data;
}
public function setSharedObj(setValue:String):void {
this.so.data.test = setValue;
this.so.flush();
}
}
When embed the compiled swf using AllowScriptAccess: "never", get Request never have setted the queryparam so.
If set AllowScriptAccess to "always" queryparam will be correctly setted
#akmozo is right, the problem was not related by AllowScriptAccess, but from my way of testing.
The problem is:
Using firefox in anonymous mode, every time you reload the page, shared object are deleted.
I thought for anonymous session are saved, it is not so!
I have some questions with sharing/using/accessing variables/functions between loaded swf files.
my prj consists of main.swf file and 2 swf's which I load on first init of the main.swf.
my questions are:
1.how can I use variables from 1.swf in 2.swf (function is running in 2.swf)
2.how can I call a function from 2.swf in 1.swf
here is the code I'm using to load the swf's:
var playerMc:MovieClip = new MovieClip();
var dbMc:MovieClip = new MovieClip();
var m2Loader:Loader = new Loader();
var mLoader:Loader = new Loader();
startLoad();
function startLoad()
{
//var mLoader:Loader = new Loader();
var mRequest:URLRequest = new URLRequest("./_player/player.swf");
mLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadMc);
mLoader.load(mRequest);
addChild(mLoader);
//var m2Loader:Loader = new Loader();
var m2Request = new URLRequest("./_db/db.swf");
m2Loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadMc2);
m2Loader.load(m2Request);
addChild(m2Loader);
}
function loadMc(event:Event):void
{
if (! event.target)
{
return;
}
playerMc = event.target.content as MovieClip;
mLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadMc);
}
function loadMc2(event:Event):void
{
if (! event.target)
{
return;
}
dbMc = event.target.content as MovieClip;
dbMc.x = -400;
m2Loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadMc2);
}
You have to stick with application domain.
In most cases you should load another swf in another application domain, but it's not really related to your question.
From loader, you must access to applicationDomain and then getDefinition. From there, you can get classes and use them in your main swf. Yes, you can read static properties.
If you need instances you should access loader#content. It is pointing to a root of loaded SWF. Root of loaded is SWF – is the instance of main class of the loaded swf.
Create a variable with no definition such as
public var MyClass;
as you can see i didnt add
public var MyClass:Class;
then in another function write
this.MyClass = this.mLoader.contentLoaderInfo.applicationDomain.getDefinition("NameOfClass") as Class;
i dont know much about this myself.. im having problems figuring out if you can only access Public static variables or if its possible to access normal public variables and possibly private variables because it is creating a new instance of the same class or however you want to word it..?
also after your write the above code .. when you want to change a varaibles this usually works for me
this.MyClass.RandomVariableName = this.MyClass.RandomVariableName + 1;
something like that..
I'm trying to load 3 different tickers in 3 different containers.
When I delete this line:
loader2.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=bl&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24¤cy=eur"));
loader3.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=bl&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24¤cy=eur"));
and load them separately they works fine:
but when i load them together, just as the written in this document in adobe, all three tickers showing the same number:
package {
import flash.display.MovieClip;
import flash.net.URLRequest;
import flash.display.Loader;
public class importExternalSWF extends MovieClip {
private var loader:Loader = new Loader();
private var loader2:Loader = new Loader();
private var loader3:Loader = new Loader();
public function importExternalSWF() {
loader.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=mrj-4&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24¤cy=eur"));
loader2.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=bl&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24¤cy=eur"));
loader3.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=grel&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24¤cy=eur"));
ticker1.addChild(loader);
ticker1.width=50;
ticker1.height=20;
ticker2.addChild(loader2);
ticker2.width=50;
ticker2.height=20;
ticker3.addChild(loader3);
ticker3.width=50;
ticker3.height=20;
}
}
}
I cant find solution anywhere
Thanks
edit
I rewrite my code to this, and its still the same result
public class importExternalSWF extends MovieClip {
public function importExternalSWF() {
var url = "http://tickers.playtech.com/jackpots/new_jackpot.swf";
var urlParams:Array = ["grel", "bl", "game=mrj-4"];
var tickers:Array = [ticker1, ticker2, ticker3];
var tickerHeight:Number = 50;
var tickerWidth:Number = 50;
loadUrls();
function loadUrls():void {
for(var i:uint = 0; i<urlParams.length; i++)
{
var urlLoader = new Loader();
var flashvars:URLVariables = new URLVariables();
flashvars["casino"] = "cityclub";
flashvars["info"] = "1";
flashvars["game"] = urlParams[i];
flashvars["currency"] = "eur";
flashvars["font_face"] = "arial";
flashvars["bold"] = "true";
flashvars["font_size"] = "10";
flashvars["bg_color"] = "0x000000";
flashvars["font_color"] = "ffffff";
var request:URLRequest = new URLRequest(url);
request.data = flashvars;
urlLoader.load(request);
tickers[i].width=tickerWidth;
tickers[i].height=tickerHeight;
tickers[i].addChild(urlLoader);
}
}
}
I suspect that the external SWF file sets some variables on the root level. Therefore each load will override the previous values and you'll end up with the same score in all "tickers".
Most likely this interference can be resolved by loading each SWF into its own ApplicationDomain. By default, SWFs are being loaded into the same ApplicationDomain and share their code.
So instead of doing this:
urlLoader.load(request);
You should do soemthing like this:
// create a new LoaderContext with a spearate ApplicationDomain
var context:LoaderContext = new LoaderContext(false, new ApplicationDomain());
// load the request and use the context with the separate ApplicationDomain
urlLoader.load(request, context);
I have bad news, i tried everything, but I can't load correctly the swf files. So, I have started to investigate this, and i found that, first, your SWF has AVM1Movie format (new_jackpot.swf), so, I conclude that this SWF was created with version 1 or 2 of ActionScript. If you see the reference of AVM1Movie Class (here the link), says the following:
There are several restrictions on an AVM1 SWF file loaded by an AVM2 SWF file:
The AVM1 SWF file that is loaded by an AVM2 SWF file cannot load another SWF file into this. That is, it cannot load another SWF file over itself. However, child Sprite objects, MovieClip objects, or other AVM1 SWF files loaded by this SWF file can load into this.
Then, i tried too, with a library that implements Threads in Flex, and found this (here this link async-threading):
The Actionscript Virtual Machine (AVM) in the Flash Player is severely limited by only having one thread...
I have created several projects using Loaders, SWFLoaders, ByteArrays, etc, all this in actionscript 3 in Flex SDK 3.2.
Maybe if you create this project in a previous version could work, or try to use same library that implements threads.
Anyway if I find something more, will edit this answer with another solution that's right.
Try adding a 1 after «laoder» at these places:
private var loader:Loader = new Loader();
loader.load(new URLRequest("http://tickers.playtech.com/jackpots/new_jackpot.swf?casino=cityclub&info=1&game=mrj-4&font_face=Arial&bold=true&font_color=FFFFFF&bg_color=240000&font_size=24¤cy=eur"));
There was no solution to this issue due to lack of compatibility from third part company that provides the tickers.
I am trying to use the Loader class to load an swf animation. If I do addChild(ldr); the animation is displayed and perma-looped, but if I try it as below, the animation doesn't display.
public var ldr:Loader;
public var explosion:MovieClip;
public var req:URLRequest;
ldr = new Loader();
req = new URLRequest("../graphics/explosion1.swf");
ldr.load(req);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);
and
public function onCompleteHandler(loadEvent:Event):void {
explosion = ldr.content as MovieClip;
addChild(explosion);
}
Any ideas? Thanks!
not sure, but it may be a simple security problem : loaderInfo.content is subject to security restrictions : http://help.adobe.com/fr_FR/AS3LCR/Flash_10.0/flash/display/LoaderInfo.html#content
so then your ldr.content as MovieClip fails silently, and explosion is null :)
addChild(ldr) should be just fine for what you're doing, but if you really need access to contentLoaderInfo.content, you should either use Security.allowDomain(domain of your main app) in your explosion1.swf or set a crossdomain policy in the repertory.
hope this helps.