Workaround for Security.allowDomain - actionscript-3

I have number of SWF files which should be accessed from external server. To be able to do this I need to have Security.allowDomain in each SWF file. The problem here is that I don't have FLA for those files and there are thousands of SWFs.
If there a better way to configure those files to be accessible from other domain?
Like having some kind of config file or so.

Yes, there is one workaround, but I think it's a security hole, so it can be fixed in any release of flash player. Meanwhile it works now so here is solution - use URLLoader with BINARY dataFormat as preloader for swf bytes:
swf without Security permissions for it scripting:
package
{
import flash.display.MovieClip;
public class astest extends MovieClip
{
public function astest()
{
}
public function externalCheck():void
{
graphics.beginFill(0xFF0000);
graphics.drawCircle(100, 100, 100);
}
}
}
Loader swf that wants to load previous swf and call the externalCheck method:
package
{
import flash.display.Loader;
import flash.display.MovieClip;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.utils.ByteArray;
public class astest2 extends MovieClip
{
private var loader:Loader;
private var urlLoader:URLLoader;
public function astest2()
{
init();
}
//this method works fine
protected function init():void
{
urlLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.load(new URLRequest("http://domain_with_your_swfs/astest.swf"));
urlLoader.addEventListener(Event.COMPLETE, function(event:Event):void
{
addChild(loader = new Loader());
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoader);
loader.loadBytes(urlLoader.data as ByteArray);
});
}
//this method will fire SecurityError when calling the 'externalCheck' method
protected function init2(event:Event = null):void
{
addChild(loader = new Loader());
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoader);
loader.load(new URLRequest("http://domain_with_your_swfs/astest.swf"));
}
protected function onLoader(event:Event = null):void
{
var swf:Object = loader.content;
swf.externalCheck();
}
}
}
Don't forget to place the crossdomain.xml file to the root of your server with swf files to load, without it URLLoader will not able to load the bytes, it's the only security requirement.

Related

AS3 debugger stops responding while trying to load image into sprite using Loader

I'm trying to create a simple Menu in AS3. There is a sprite called startButton, which when pressed will call the function startGame, and that's it! But, not so easy. I'm using flashdevelop IDE so I'm trying to call a loader to get a .png image file for the spite startButton. But, it doesn't work. There are no error messages, the debugger just does not respond. Any help? Here is the code for both files
Main code:
package {
//Other Files
import Menu;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
public class Main extends Sprite {
//Game values
public static var gameWidth:int = 750;
public static var gameHeight:int = 750;
public function Main() {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
addChild(Menu.startButton);
Menu.startButton.addEventListener(MouseEvent.CLICK, startGame);
stage.addEventListener(Event.ENTER_FRAME, update);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
}
//Function starts game
public function startGame(evt:MouseEvent):void {
removeChild(Menu.startButton);
}
//Updates every 60 seconds
public function update():void {
trace("Updated");
}
}
}
And Menu Image code:
package {
//Other files
import Main;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
public class Menu extends Sprite {
public static function imageLoaded():void {
startButton.addChild(loader);
//initizlize values for startButton Bitmap
startButton.x = (Main.gameWidth / 2) - (startButton.width / 2);
startButton.y = (Main.gameHeight / 2) - (startButton.height / 2);
}
//create startButton Bitmap
public static var startButton:Sprite = new Sprite();
public static var loader:Loader = new Loader();
loader.load(new URLRequest("lib/menustartbutton.png"));
loader.addEventListener(Event.COMPLETE, imageLoaded);
}
}
By the way, I wait for the loader to successfully load the image before working with it, just in case the image takes more time and it draws errors.
The problem is that you misuse static. all static methods/properties are initialized before the classes themselves. As a result static can receive values but they cannot run any code. Running code has to happen after all classes are ready to go which is not the case when static is initialized. In your case startButton and loader are created correctly but the next line never runs 'loader.load'.
Don't misuse static, you are obviously trying to use static to make you code writing and life easier but at the end because you are misusing it you will always end up with more problems.

AS3: Display data(integer) from an swf to another swf through class

I have a "score1.as" class in which it will access a data from an swf and display it into
my "finalscore.fla"...I was able to pass and trace the data successfully into my "finalscore.fla"..But my problem is this: Though I was able to access the data by tracing it, I can't display it to my dynamic text...I thought by simply typing "txtScore.text = ("Score: " + lol1.go() );" would solve the problem but it didn't...Please help..Here's my code..bY the way, I'm using actionscript 3.0..
score1.as:
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
public class score1 extends Sprite
{
private var loader:Loader;
public function Parent()
{
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
loader.load(new URLRequest("savescore.swf"));//This is the swf where in the data came from
}
public function onLoaded(e:Event):void
{
trace(loader.content['currentScore']);
}
public function go():int{
return loader.content['currentScore'];//This is the data being accessed
}
}
}
finalscore.fla:
var lol1:score1 = new score1();
txtScore.text = ("Score: " + lol1.go() ); // This is where I can't display the data
lol1.Parent();//I successfully traced the data
Check your embedded fonts. You are likely only embedding the characters from the font that were present at compile time. For example, if you have a textfield with "Hello World!", and you wanted to do textfield.text = "Jiggly Jello Lord!" would display as "l ello ord", because only those characters were present in the textfield during compile.
Edit:
I took a closer look at your code. You need to call Parent() before you can get your content. In fact, rename it to be the constructor, and you should be good.
package {
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
public class score1 extends Sprite {
public var loader:Loader;
public function score1() {
// You need to run this code as your constructor.
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
loader.load(new URLRequest("savescore.swf"));
}
public function onLoaded(e:Event):void {
trace(loader.content['currentScore']);
}
public function go():int {
return loader.content['currentScore'];
}
}
}
You'd also want to wait for your content to be loaded before accessing the data. For this, you'd need to wait for your onLoaded to fire before trying txtScore.text = ("Score: " + lol1.go() );
Edit 2
onLoaded is how you know if it runs. It gets called when Event.COMPLETE fires. By the same extension, just register for that event from outside your class, or fire an event, or any other solution that completes after the data is loaded.
finalscore.fla:
var lol1:score1 = new score1();
lol1.loader.contentLoaderInfo.addEventListener(Event.COMPLETE, scoreReady);
function scoreReady(e:Event):void {
txtScore.text = "Score:" + lol1.go();
}

play flv using netStream appendBytes

I know that there are many ways to play an FLV file but considering my project requirements, I need to play the flv using URLStream and NetStream
here's the complete sample code that I'm doing my tests on:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.NetStatusEvent;
import flash.events.ProgressEvent;
import flash.utils.ByteArray;
import flash.net.URLRequest;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.NetStreamAppendBytesAction;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.net.URLStream;
/**
* ...
* #author Hadi Tavakoli
*/
public class Main extends Sprite
{
private var netConnection:NetConnection;
private var netStream:NetStream;
private var ul:URLStream;
private var video:Video;
private var bytes:ByteArray = new ByteArray();
private var _isSeek:Boolean = false;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
video = new Video();
addChild(video);
netConnection = new NetConnection();
netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnectionStatusHandler);
netConnection.connect(null);
}
private function netConnectionStatusHandler(ev:NetStatusEvent):void
{
switch(ev.info.code)
{
case 'NetConnection.Connect.Success':
ul = new URLStream();
ul.addEventListener(ProgressEvent.PROGRESS, onProgress);
ul.load(new URLRequest('01.flv'));
break;
}
}
private function onProgress(e:ProgressEvent):void
{
ul.readBytes(bytes, bytes.length);
if (!netStream)
{
netStream = new NetStream(netConnection);
netStream.client = { };
video.attachNetStream(netStream);
netStream.play(null);
trace("BEGIN")
netStream.appendBytesAction(NetStreamAppendBytesAction.RESET_BEGIN);
}
else
{
if (!_isSeek)
{
trace("SEEK")
netStream.appendBytesAction(NetStreamAppendBytesAction.RESET_SEEK);
_isSeek = true;
}
}
if (bytes.length == e.bytesTotal)
{
trace("END")
netStream.appendBytesAction(NetStreamAppendBytesAction.END_SEQUENCE);
}
netStream.appendBytes(bytes);
trace("-")
}
}
}
I'm not sure if I am using "appendBytes" method correctly? the video is shown but only a very few first frames will play and then the video stops!
in my eyes it seems all ok! do you have any advice on where my problem is?
I don't think you need the if (!_isSeek) block. It looks like you are pushing the bytes as you receive them in a sequential order and so there's never a seek. It looks like it will push the first set of bytes and then append a seek action and append the rest of the bytes. Try just removing that block and see if it works.
Otherwise I think it's ok.
in "ul.readBytes(bytes, bytes.length);" line, there is a bug i guess. It's never worked for me also. It always return full length (from 0 to the available bytes). So It have a huge memory leak. But if you are using flash player 11.4 or later, you can change it like this.
ul.position = bytes.length;
ul.readBytes(bytes);

gotoAndPlay in embedded movieclip

I am working on an Air 2.6 project with an embedded SWF.
I am using the following embed code:
[Embed(source = "../../assets/click_feedback.swf", symbol="sub_circle")]
[Bindable]
public static var click_feedback:Class;
And the following code to get an instance of the click_feedback class:
private var cfb:MovieClip = new Assets.click_feedback() as MovieClip
The problems are:
The asset sub_circle has a frame labeled 'respond'. However, it just plays non stop whether or not the label is called with gotoAndPlay.
And, at the end of the animation, there is an Event.COMPLETE called, which is not being picked-up by my code.
I have tested the sub_circle asset in CS5 where I built it, and, in that environment it does not animate until 'respond' is called, and the event it triggers can be heard by my script.
Is this the correct way to handle embedded assets from an SWF?
Embedding of separate symbols from swf in general isn't a good idea:
It slows the compilation of your project, because of compiler must transcode swf format.
Embedding delete ALL AS code from timeline (I didn't check, but may be it remove labels as well, and it can be the reason of your issue).
I recommend embed the hole swf file and loads its bytes in runtime, a little more code to handle the async loading, but much more freedom and flexibility in use:
you safe all as3 code
you can choose ApplicationDomain where to load classes
you can easily switching from Embedding to runtime swf loading by url at any time, if you want to separate the as code and art/sounds assets.
organize your assets to library with the AssetsManager (with api like load(ByteArray or URL), getSkin(name):DisplyObject)
Code example adapted for your assets:
package
{
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.utils.ByteArray;
[SWF(width="800", height="200", backgroundColor="0x8B8B8B")]
public class astest extends Sprite
{
[Embed(source="../../assets/click_feedback.swf", mimeType="application/octet-stream")]
private static const common_art:Class;
private var loader:Loader;
private var domain:ApplicationDomain = ApplicationDomain.currentDomain;
public function astest()
{
init();
}
public function init():void
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
var loaderContext:LoaderContext = new LoaderContext(false, domain);
loaderContext.allowCodeImport = true;
loader.loadBytes(new common_art() as ByteArray, loaderContext);
}
private function onLoaded(event:Event):void
{
var clip:MovieClip = getSkin("sub_circle") as MovieClip;
addChild(clip);
}
private function getSkin(name:String):DisplayObject
{
if(domain.hasDefinition(name))
{
var clazz:Class = domain.getDefinition(name) as Class;
return new clazz() as DisplayObject;
}
return null;
}
}
}

Flash Builder 4.6 Mobile Flex AS3: How to communicate with embedded SWF

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