I've generated a class to load and unload SWFs, however, it does not seem to load to swf visually, but it doesn't return any errors either.
Parent code:
//specify the path for the child SWF
var PageURL:URLRequest = new URLRequest("home/home_index.swf");
//include the SWF loading class
import MM_swfloader;
var mainPage:MM_swfloader = new MM_swfloader();
//evoke the load
mainPage.LoadSWF(PageURL);
MM_swfloader class:
package {
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
/**
* author: Me
* email: lala#lala.com
**/
public class MM_swfloader extends Sprite {
public var loader:Loader = new Loader();
public function MM_swfloader():void
{
// constructor code
}
public function LoadSWF(val:URLRequest):void{
var loader:Loader = new Loader();
loader.load(val);
addChild(loader);
trace("loaded"); //returns true
}
public function UnLoadSWF():void {
loader.unload();
}
}
}
I don't understand where the loaded SWF is being loaded to. Any ideas?
You need to add the instance of your SWF loading class to the stage in the parent class:
//specify the path for the child SWF
var PageURL:URLRequest = new URLRequest("home/home_index.swf");
//include the SWF loading class
import MM_swfloader;
var mainPage:MM_swfloader = new MM_swfloader();
// add the instance to the stage
this.addChild(mainPage);
//evoke the load
mainPage.LoadSWF(PageURL);
There are also a couple of problems with the code in your loader class which I have fixed below (see the comments for an explanation):
// Poor practice to use the default namespace, stick it in com.lala
package {
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
/**
* author: Me
* email: lala#lala.com
**/
public class MM_swfloader extends Sprite {
public var loader:Loader = new Loader();
public function MM_swfloader():void
{
// constructor code
// listen for loader complete on the loader instance
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler);
// add loader to stage
this.addChild(loader);
}
// Note that by convention loadSWF would be a better name for this method
public function LoadSWF(val:URLRequest):void {
// commented out to avoid creating a new locally-scoped
// loader each time the method is called
//var loader:Loader = new Loader();
loader.load(val);
// commented out to avoid adding child each time
// method is called, added in constructor instead
//addChild(loader);
// loading is asynchronous, this needs to be in a handler
// for the loader.complete event
//trace("loaded"); //returns true
}
// call this unloadSWF
public function UnLoadSWF():void {
loader.unload();
}
// handler for loader.complete event
private function loaderCompleteHandler(event:Event):void {
trace("loaded");
}
}
}
You need to add the loader content to the stage on complete, like so:
import flash.net.URLRequest;
import flash.display.Loader;
import flash.events.Event;
import flash.events.ProgressEvent;
function startLoad()
{
var mLoader:Loader = new Loader();
var mRequest:URLRequest = new URLRequest("someswf.swf");
mLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);
mLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressHandler);
mLoader.load(mRequest);
}
function onCompleteHandler(loadEvent:Event)
{
addChild(loadEvent.currentTarget.content);
}
function onProgressHandler(mProgress:ProgressEvent)
{
var percent:Number = mProgress.bytesLoaded/mProgress.bytesTotal;
trace(percent);
}
startLoad();
Related
This happens on many occasions when loading content from the web, but for us, it's most common loading images through Facebook's graph shortcut call.
Something as simple as:
package
{
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
import flash.system.LoaderContext;
public class RedirectTestFail extends Sprite
{
private const url:String = 'https://graph.facebook.com/4/picture';
private const context:LoaderContext = new LoaderContext(true);
public function RedirectTestFail()
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
loader.load(new URLRequest(this.url), this.context);
}
protected function onComplete(event:Event):void
{
this.addChild((event.target as LoaderInfo).content);
}
}
}
Gives a dreaded "SecurityError: Error #2122" error.
Despite other answers suggesting something as simple as:
Security.loadPolicyFile("https://fbcdn-profile-a.akamaihd.net/crossdomain.xml");
This isn't clear, nor comprehensive enough. Facebook have different image servers, that I've which I've been caught with before. This could be deemed a Flash Player Bug, which I'd accept, but as a security concern, I can understand them not allowing a redirect by default, as in you should handle it yourself.
I now use below. You try to do your normal behaviour, but wrap it in a try/catch for SecurityError. If one is thrown, catch it, and if the domain of the loaderInfo is different to the domain you requested, you run a 'Security.allowDomain' and 'Security.loadPolicyFile' on it, and attempt to load it one more times. This works perfectly in practise, with only a tiny amount of overhead.
package
{
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.system.Security;
public class RedirectTest extends Sprite
{
private const url:String = 'https://graph.facebook.com/4/picture';
private const context:LoaderContext = new LoaderContext(true);
public function RedirectTest()
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
loader.load(new URLRequest(this.url), this.context);
}
protected function onComplete(event:Event):void
{
try
{
this.addChild((event.target as LoaderInfo).content);
}
catch(error:SecurityError)
{
trace(error);
var loaderInfo:LoaderInfo = (event.target as LoaderInfo);
var loaderDomain:String = loaderInfo.loader.contentLoaderInfo.url;
if(-1 == this.url.indexOf(loaderDomain))
{
Security.loadPolicyFile(loaderDomain + 'crossdomain.xml');
if( 0 == loaderDomain.indexOf('https') )
{
Security.allowDomain(loaderDomain);
}
else
{
Security.allowInsecureDomain(loaderDomain)
}
loaderInfo.loader.load(new URLRequest(this.url), this.context);
return;
}
throw error;
}
}
}
}
if you no need to manipulate pixels with loaded image BitmapData object, then you can just remove context from the loader.load
but without context.checkPolicyFile = true you will cant add smoothing to image
So, my menu for my game is in a separate .fla file and I have used a loader like so to load the menu into my game:
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.DisplayObject;
import flash.display.Stage;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.ui.Mouse;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.text.TextFormat;
import flash.text.TextField;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.net.URLLoader;
import flash.system.LoaderContext;
import flash.display.Sprite;
import flash.net.Socket;
import caurina.transitions.Tweener;
public class Main extends MovieClip {
public static var gameLayer:Sprite = new Sprite;
public static var endGameLayer:Sprite = new Sprite;
public static var menuLayer:Sprite = new Sprite;
public var gameTime:int;
public var levelDuration:int;
public function Main()
{
addChild(gameLayer);
addChild(endGameLayer);
addChild(menuLayer);
var myMenu:Loader = new Loader();
var url:URLRequest = new URLRequest("Menu.swf");
myMenu.load(url);
myMenu.contentLoaderInfo.addEventListener(Event.COMPLETE, menuLoaded);
function menuLoaded(event:Event):void
{
menuLayer.addChild(myMenu.content);
}
playBtn.addEventListener(MouseEvent.CLICK, startGame);
}
public function startGame(e:Event)
{
// Code to remove the menu (menuLayer.removeChild?)
// Code here to start timers etc
}
I set instance names for my buttons but when I try to do something like menuLayer.playBtn.addEventListener(MouseEvent.CLICK, startGame);, I get messages saying Access of undefined property playBtn.
Now, I double checked on my Menu.fla and I definitely gave the button an instance name of playBtn but it's not working. Any help please? Might be something really obvious I've missed but I'm not sure what.
EDIT: Trying it another way (Converting the menu to a movieclip) but not 100% sure how to do it exactly. The code I have is:
public class Main extends MovieClip {
var mainMenu:menuMain = new menuMain;
// Other variables
public function Main()
{
addChild(gameLayer);
addChild(endGameLayer);
addChild(menuLayer);
menuLayer.addChild(mainMenu);
mainMenu.addEventListener(Event.COMPLETE, menuLoaded);
}
function menuLoaded(event:Event):void
{
//var mainMenu:LoaderInfo = event.currentTarget as LoaderInfo;
//var menuInstance:MovieClip = menuLayer.getChildAt(0) as MovieClip;
// now you can actually add the listener, because the content is actually loaded
mainMenu.playBtn.addEventListener(MouseEvent.CLICK, startGame);
}
public function startGame(e:Event)
{
// Code to execute timers etc.
}
My guess is that you think that when you go menuLayer.addChild(myMenu.content) that menuLayer suddenly becomes an instance of menu.swf That is not the case. It becomes a child of menuLayer.
Try this :
menuLayer.addChild(myMenu.content);
var menuInstance:MovieClip = menuLayer.getChildAt(0) as MovieClip;
trace (menuInstance.playBtn);
This code assumes that you have nothing else added to menuLayer and in that case your menu.swf content would be the only child on the display list of menuLayer.
I am also assuming that menu.swf's contents are a MovieClip.
If my assumptions are wrong, this may not work.
I also noticed that you have your menuLoaded method inside your constructor. Not a good idea. Especially since the next line is expecting playBtn to exist and the menu hasn't even been loaded.
Try something like this :
public function Main()
{
addChild(gameLayer);
addChild(endGameLayer);
addChild(menuLayer);
var myMenu:Loader = new Loader();
var url:URLRequest = new URLRequest("Menu.swf");
myMenu.load(url);
myMenu.contentLoaderInfo.addEventListener(Event.COMPLETE, menuLoaded);
}
function menuLoaded(event:Event):void
{
var myMenu:LoaderInfo = event.currentTarget as LoaderInfo;
menuLayer.addChild(myMenu.content);
var menuInstance:MovieClip = menuLayer.getChildAt(0) as MovieClip;
// now you can actually add the listener, because the content is actually loaded
menuInstance.playBtn.addEventListener(MouseEvent.CLICK, startGame);
}
public function startGame(e:Event)
{
// Code to remove the menu (menuLayer.removeChild?)
// Code here to start timers etc
}
I have a Flash Barcode scanner (camera) and want to use it in a mobile project to scan QR-Codes. It would be nice that it is possible to re-use this SWF and embedded it into a mobile Flex application. The SWF is made in Flash CS5.
So far, embedding (and add it to the stage and showing it) is successful but how do i communicate with the SWF? For example calling a function of it or by using events.
Here is a code snippet:
[Embed(source="../cam/cam.swf")]
private var cam:Class;
....
....
public const EVT_SNAPSHOT : String = "onSnapShot";
public var camera : Object;
public function onInit(e:Event) : void
{
this.camera = new cam();
this.camera.addEventListener(Event.ADDED_TO_STAGE, this.cameraInit );
this.stage.addChild( this.camera as DisplayObject );
}
private function cameraInit(e:Event):void
{
trace( 'Added to stage' );
this.stage.addEventListener( EVT_SNAPSHOT, this.cameraDoScan ); // does not bind?
trace( this.camera.hasOwnProperty('getAppInfo') ); // shows 'false'
}
private function cameraDoScan(e:MouseEvent):void
{
trace('MouseClick!');
}
Does anyone know to communicate with this 'thing'?
The most functional way to use external swf module is to load it into current ApplicationDomain, so you will have access to all classes contained in this loaded swf:
package
{
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.utils.ByteArray;
import flash.utils.getDefinitionByName;
public class astest extends Sprite
{
[Embed(source="/../assets/art.swf", mimeType="application/octet-stream")]
private static const art:Class;
public function astest()
{
var artBytes:ByteArray = new art() as ByteArray;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onArtLoaded);
loader.loadBytes(artBytes, new LoaderContext(false, ApplicationDomain.currentDomain));
}
protected function onArtLoaded(e:Event):void
{
var domain:ApplicationDomain = ApplicationDomain.currentDomain;
if(domain.hasDefinition("welcome_view"))
{
var moduleClass:Class = domain.getDefinition("welcome_view") as Class;
var module:Object = new moduleClass();
//module.moduleFunction();
addChild(module as DisplayObject);
}else
{
trace("loaded swf hasn't class 'welcome_view'");
}
}
}
}
I am trying to parse an xml file and load Flex modules dynamically in my application. But it loads only the last module everytime. I have a singleton class which does the parsing and loading of modules. Here is the class
package
{
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import mx.controls.Alert;
import mx.events.ModuleEvent;
import mx.modules.IModuleInfo;
import mx.modules.ModuleLoader;
import mx.modules.ModuleManager;
public class VappModuleManager
{
private static var _instance:VappModuleManager;
private static const MODULE_PATH:String="./com/emc/vapp/";
private static const MANIFEST_PATH:String="module-manifest.xml";
private var _module:IModuleInfo;
private var _handler:Function;
private var loader:URLLoader;
public function VappModuleManager(object:SingletonEnforcer)
{
}
public function set handler(handler:Function):void
{
_handler=handler;
}
public static function get instance():VappModuleManager
{
if(_instance==null)
{
_instance=new VappModuleManager(new SingletonEnforcer());
}
return _instance;
}
public function load():void
{
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, xmlLoaded);
loader.load(new URLRequest(MANIFEST_PATH));
}
private function xmlLoaded(event:Event):void
{
Alert.show("Event Completed");
var manifest:XML=new XML(event.target.data);
Alert.show(manifest.module.length());
for (var index:int=0;index<manifest.module.length();index++)
{
Alert.show(MODULE_PATH+manifest.module[index].#name);
_module=ModuleManager.getModule(MODULE_PATH+manifest.module[index].#name);
_module.addEventListener(ModuleEvent.READY,_handler);
_module.load();
}
}
}
}
internal class SingletonEnforcer {}
I use the above class as follows.
moduleManager=VappModuleManager.instance;
moduleManager.handler=myhandler;
moduleManager.load();
I understand the problem is with eventlistener for variable "_module" but dont know how to solve it. Any help appreciated.
The call to IModuleInfo.load is asynchronous so your for loop has run completely before any of the modules have loaded. Also, your class level _module property is overwritten by a new Module instance each time the loop iterates.
I'd suggest loading each module sequentially by waiting for the READY event and initiating the load of the next module only when it has fired. I'd also fire an event when all the modules are loaded instead of executing a callback function as this will give you more flexibility (multiple objects can listen for an event for example).
The following isn't tested, but should give you the idea:
package
{
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import mx.controls.Alert;
import mx.events.ModuleEvent;
import mx.modules.IModuleInfo;
import mx.modules.ModuleLoader;
import mx.modules.ModuleManager;
public class VappModuleManager
{
private static var _instance:VappModuleManager;
private static const MODULE_PATH:String="./com/emc/vapp/";
private static const MANIFEST_PATH:String="module-manifest.xml";
private var loader:URLLoader;
private var manifest:XML;
private var loadCount:int = 0; // track loaded modules
public function VappModuleManager(object:SingletonEnforcer)
{
}
public static function get instance():VappModuleManager
{
if(_instance==null)
{
_instance=new VappModuleManager(new SingletonEnforcer());
}
return _instance;
}
public function load():void
{
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, xmlLoaded);
loader.load(new URLRequest(MANIFEST_PATH));
}
private function xmlLoaded(event:Event):void
{
manifest =new XML(event.target.data);
// load the first module
loadModule();
}
private function loadModule() {
// Use a locally scoped variable to avoid writing over the previous instance each time.
// You could push these onto an array if you need to be able to access them later
var module:IModuleInfo = ModuleManager.getModule(MODULE_PATH+manifest.module[loadCount].#name);
module.addEventListener(ModuleEvent.READY, moduleReadyHandler);
module.load();
}
private function moduleReadyHandler(event:ModuleEvent) {
// Remove the event listener on the loaded module
IModuleInfo(event.target).removeEventListener(ModuleEvent.READY, moduleReadyHandler);
loadCount ++;
// Are there still modules in the manifest to load?
if (loadCount < manifest.module.length()) {
// Yes... load the next module
loadModule();
} else {
// No... we're all finished so dispatch an event to let subscribers know
dispatchEvent(new Event("complete"));
}
}
}
}
I have an an class a fla called draw.fla . The document class associated with draw is Draw.as The code inside Draw.as is as follows
package
{
import flash.display.MovieClip;
import flash.display.Graphics;
public class Draw extends MovieClip
{
public function drawCircle1(color:Number):void
{
graphics.beginFill(color);
graphics.drawCircle(100,100,40);
graphics.endFill();
}
}
}
The resulting swf is called draw.swf.
I have another fla called test.fla.
The following is the code on the first frame on the main time line.
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.display.Loader;
var swfLoader = new Loader();
var color:Number;
color = Math.round(Math.random()*0xFFFFFF);
var urlReq:URLRequest = new URLRequest("draw.swf");
swfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoadComplete);
swfLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, swfLoadError);
swfLoader.load(urlReq);
function swfLoadComplete(evt:Event):void
{
var loader:Loader = Loader(evt.target.loader);
addChild(loader.content);
swfLoader.removeEventListener(Event.COMPLETE, swfLoadComplete);
}
function swfLoadError(evt:IOErrorEvent):void
{
trace("Unable to load swf ");
swfLoader.removeEventListener(IOErrorEvent.IO_ERROR, swfLoadError);
}
I have loaded dwaw.swf into test.swf as you can see. Is there anyway I can access the drawCircle1 function of Draw from the test.fla. Actually I need to pass the value color as an argument while accessing this function.
If I'm not wrong, once the loader is complete you could simply make MovieClip(loader.content).drawCircle1(0xFF0000);.
Loader.content should be that class, and function can be called by name with square bracket syntax:
function swfLoadComplete(evt:Event):void
{
var loader:Loader = Loader(evt.target.loader);
addChild(loader.content);
//trying to call function drawCircle1
loader.content["drawCircle1"](0xFF0000);
swfLoader.removeEventListener(Event.COMPLETE, swfLoadComplete);
}