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..
Related
I have an application in AIR, which is loading swf files and makes previews of them. When those swfs loads other content (eg. jpg) then i have an error, that url not found - i am convinced that is about jpg file. This problem shows only when i load swf by filereference using loadBytes(). When i load swf by Loader using load() - problem doesn`t exist. How can i fix this issue? Sorry for my english. I attach code fragment with loading swfs.
private static function loadFile(loadType:String, swfNum:Number = 0):void {
lc = new LoaderContext();
lc.allowCodeImport = true;
lc.allowLoadBytesCodeExecution = true;
currentSwfNum = swfNum;
var fRef:FileReference = DataBase.swfsList[currentSwfNum];
fRef.addEventListener(Event.COMPLETE, onFileReferenceLoad);
fRef.load();
}
private static function onFileReferenceLoad(e:Event):void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, ifComplete);
loader.loadBytes(e.target.data, lc);
}
private static function ifComplete(e:Event):void {
var mc:MovieClip = LoaderInfo(e.target).content as MovieClip;
mc.addEventListener("SHOOT", SwfSingleCapture.captureSingleShoot);
}
DataBase.swfList - it is an array of FileReference objects, which are selected by FileReferenceList and browse().
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 have 2 swf files. One is loaded and loading an externally loaded swf into it.
Here is the code in the first loaded swf: #1
var logo:Loader = new Loader();
logo.load(new URLRequest("images/Logo.png"));
logo.contentLoaderInfo.addEventListener(Event.COMPLETE, LoadLogo);
function LoadLogo(e:Event):void
{
addChild(logo);
}
/// The SWF I AM LOADING
var Beau:Loader = new Loader();
Beau.load(new URLRequest("Beau.swf"));
Beau.contentLoaderInfo.addEventListener(Event.COMPLETE, LoadBeau);
function LoadBeau(e:Event)
{
addChild(Beau);
}
NOW HERE IS THE CODE FOR THE BEAU SWF LOADED: #2
import flash.display.MovieClip;
bird.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler);
function fl_MouseClickHandler(event:MouseEvent):void
{
//// I WANT TO BE ABLE TO ADD CODE TO CONTROL MOVIECLIPS
//// AND CHILDREN form this externally loaded swf. How do
//// I do that? Below code does not work.
var logo:MovieClip;
var ControlLogo:MovieClip = MovieClip(logo.content);
ControlLogo.alpha = .3;
}
EDIT
ok your code and tutorials are great. I am having major SANDBOX issues now when I make the clip load from an external URL. I am also coding for an ANDROID using FLASH CS5.5. Its not allowing me to use Security.allowDomain("*");
BOTTOME LINE IS THE NEWLY LOADED SWF can not access the PARENT WITHOUT PERMISSION BUT I DON'T KNOW HOW TO GIVE IT PERMISSION.... using the AIR/ANDROID PLAYER.
use property parent
parent gives loader
parent.parent gives swf#1
So you can write function as given below
function fl_MouseClickHandler(event:MouseEvent):void
{
var swf1:Object = parent.parent;
var logo:Loader = swf1.logo;
var ControlLogo:Bitmap = Bitmap(logo.content); // because logo loads an image
ControlLogo.alpha = .3;
}
make sure that logo is not a local variable, but global and public in swf#1
public var logo:Loader = new Loader();
EDIT:
logo:Loader gets added to SWF#1. Loads image, so content is Bitmap.
beau:Loader gets added to stage. Loads swf (SWF#2), so content is MovieClip.
so now
root is SWF#1
parent of beau is SWF#1
parent of SWF#2 is beau and parent of beau is SWF#1
so for SWF#2, SWF#1 is parent of parent so parent.parent
If you are not creating public variables, you can manage this by using property name.
var logo:Loader = new Loader();
logo.name = "logo";
...
...
var beau:Loader = new Loader();
beau.name = "beau";
...
...
Then anywhere in swf#2
var swf1:Object = parent.parent;
var logo:Loader = Loader(swf1.getChildByName("logo"));
....
....
For accessing the content it is recommended to use type casting as I have shown
var ControlLogo:Bitmap = Bitmap(logo.content); // because logo loads an image
so that you can check as shown below and avoid runtime errors
var ControlLogo:Bitmap = Bitmap(logo.content);
if(ControlLogo){
}
If you want to so something irrespective of content do as shown below
var ControlLogo:Object = logo.content;
if(ControlLogo && ControlLogo.hasOwnProperty("alpha")){
ControlLogo.alpha = 0.4;
}
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?
Hey there, I was wondering if this is possible to do
I am able to load the image in and have it displayed easily enough by using addChild(myLoader); where myLoader is in the classWide private scope.
The problem is, whenever I call my function inside that class which adds the loader to the stage, it clears the old one and puts this new one in even if I add a bit where I change myLoader.name to something related to how many images it has completed.
This is a serious hinderance as I can't do anything besides KNOW how many images I will need to load and write the code X times. The problem being is that the urls are read from an XML file.
My main desire was to have a classWide private Array which contained my loaders and I would assign them using myArray.push(myLoader) each time the load had completed. There is a problem which is that it compiles but they never get displayed
it would work as this is written
public class Images extends Sprite
{
private var imagesLoaded = 0;
private var myLoader:Loader;
...
public function Images():Void
{
myLoader = new Loader;
//loop calling a myLoader.load(imageURL) for a bunch of urls
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
}
public function imageLoaded
{
myArray[imagesLoaded] = myLoader;
trace("does\'nt get to here!!");
addChild(myArray[imagesLoaded]);
imagesLoaded++;
}
}
You could create multiple Loaders to load your multiple files:
public class Images extends Sprite
{
private var imagesLoaded = 0;
private var myArray:Array;
...
public function Images():Void
{
myArray = [];
for each (var url:String in myBunchOfURLS)
loadURL(url);
}
private function loadURL(url:String):void
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
loader.load(new URLRequest(url));
// you'll need to add the loader to the display list to see anything!
addChild(loader);
}
private function imageLoaded(event:Event):void
{
var info:LoaderInfo = LoaderInfo(event.currentTarget);
info.removeEventListener(Event.COMPLETE, imageLoaded);
var loader:Loader = info.loader;
myArray[imagesLoaded++] = loader;
// or you could add the loader to the display list here instead?
}
}
If you have to have one loader, then you'll need to wait for each load to complete, get the bitmap data out of the loaded bitmap, add it to a new bitmap, then start loading the next image. That's a bit more of a pain - I'd stick to this approach if I were you.