how to load swf immediately from local data - actionscript-3

i want to save the swf data in local so i can recreate it again and again.though most web browser has cache mechanism ,once a resource is downloaded,the application can get the resource from the local. but the browser still need to check the remote server's file's time stamp to make sure the remote file was not updated.that's make the process delay.
i want to handle it by myself ,so i save the downloaded data in the application.the trouble is i didn't find a way to recreate a new instance of the loaded swf immediately.for example,if i download a jpeg file,i finally got a bitmapdata , so i keep the bitmapdata,if i need a copy,i simply use clone() . but swf is different,i dont know how to clone the swf instance.
my way is load swf as binary array,and load it by Loader.loadBytes,here's my code.
public static function loadSWFByte(data:ByteArray,callback:Function,domain:ApplicationDomain):void{
var loader:Loader = new Loader();
var f:Function = function(e:Event):void{
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,f);
if(callback!=null){
callback(loader.content,loader.contentLoaderInfo);
}
}
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,f);
loader.loadBytes(data,new LoaderContext(false,domain));
}
if i need to create it,i always use callback,thus make coding complicated.Is there a way i can get the instance without using callback?

Loading SWF bytes or from URL is always async , but You can load it once and clone each time:
// when loader load is complete
var cl:Class = loader.content["constructor"];
var clone:* = new cl();

Related

Flash SWF, reading the file contents from inside the browser, possible?

I have an actionscript project which I deploy as both a Air desktop application and in the browser using the Flash plugin.
My desktop deployment reads the SWF file itself, creates a hash of the file and send it to my server. If the hash does not match whats expected the SWF then uploads itself to my server for further examination. This all uses the flash.filesystem libraries.
Can the same be done when deployed as Flash file in the browser. I do not have access to flash.filesystem for browser deployment.
Does a way other than using filesystem exist to read the SWF itself.
According to this article (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/Worker.html) your entire SWF content is accessible via loaderInfo.bytes:ByteArray so there's no need to load anything. Enjoy.
Fallback to loading:
var aRequest:URLRequest = new URLRequest;
// Property loaderInfo.url contains the full path to the SWF.
aRequest.url = loaderInfo.url;
var aLoader:URLLoader = new URLLoader;
// Set data format to binary instead of default text.
aLoader.dataFormat = URLLoaderDataFormat.BINARY;
aLoader.addEventListener(Event.COMPLETE, onReady);
aLoader.load(aRequest);
function onReady(e:Event):void
{
var anSWF:ByteArray = aLoader.data as ByteArray;
trace(anSWF.length);
}
To get the SWF bytes, use URLStream API to receive bytes into some bytearray variable.
You can then use ByteArray API to read (process) the bytearray.
You can deploy your Flex code to an AIR desktop application, which is translated to a SWF file, which can be used in browsers as an embedded object.
Please read more here.

Flash sandbox not enabling me getting JSON data from server - AS3

i'm setting up a local SWF file that has to display some JSON data retrieved from a remote web server in some dynamic text fields.
Code:
Security.allowDomain("api.yourserver.com");
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest("http://api.yourserver.com/yourendpoint");
request.method = URLRequestMethod.GET;
request.contentType = "application/json";
loader.load(request);
loader.addEventListener(Event.COMPLETE, decodeJSON);
function decodeJSON(event:Event):void{
var loader:URLLoader = URLLoader(event.target);
var Info:Object = JSON.parse(loader.data);
cont.textfield1.text = Info.text.field1;
cont.textfield2.text = Info.text.field2;
cont.textfield3.text = Info.text.field3;
}
Control > Test - It works. When run standalone it doesn't. I get the 2028 error (sandbox violation).
What i tried:
The LoaderContext method explained here on StackOverflow but i get a 2124 error (Loaded file is an unknown type - seems like the Loader method can only be used with stuff like SWF or medias like JPG etc.);
Setting local playback as described always here on StackOverflow but it didn't help;
Setting up and exception in the Global Flash Player Trust directory as explained here but got the 2028 again;
Anyone who was able to overcome this and willing to explain how or at least pointing in the right direction?
Thanks in advance!
I think that your current published file has just assess to local files only and not network ones, that's why you got security #2028 error.
To avoid that, you can change the Local playback security for your published swf from the Publish Settings to Access network only :
If you still get security errors when testing locally ( like #2048 error ), take a look on my answer of this question to add your local swf file to the trusted locations ...
Hope that can help.

Is it possible to retrieve xml from server, save to device and use that local file for my HTTPService url?

I have an app that retrieves XML From a server I run... Im trying to limit the calls to the server (if possible) to improve responsiveness of the app and decrease the likelihood that the user will get errors if the data stream doesnt make the trip successfully for whatever reason -- i get some intermittent network monitor errors, it could be due to some wifi channel conflicts I think I have, but its still is a potential weak point in the overall process and if I can work around that need to call to the server each time the user performs an 'action' within the app.
what I'd like to do is use the local storage on the device to (upon launch of the app) retrieve and save the XML data, then change my httpservice url the local file.
I have some code I used before to successfully write and read config settings to a local text file, so Im pretty sure this can be achieved, just not sure how exactly to go about it.
thanks for any light someone can shed on this or any code examples anyone can share.
Load it by default from the applicationStorageDirectory if it doesnt exist donwload and save the xml to the applicationStorageDirectory
to load:
var xmlFile:File = File.applicationStorageDirectory.resolvePath("data.xml");
if (xmlFile.exists)
{
var fileStream:FileStream = new FileStream();
fileStream.open(xmlFile, FileMode.READ);
var xml:XML = XML(fileStream.readUTFBytes(fileStream.bytesAvailable));// you will want to declare outside this scope, its just for show
fileStream.close();
}else{
downloadAndSaveXML();// if it doesnt exist dowload it then save it and call load again!
}
to save:
//download .xml first and save in the onComplete handler, im calling the file "xml"
var file:File = File.applicationStorageDirectory.nativePath("data.xml");
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
stream.writeUTFBytes(xml.toXMLString());
stream.close();
get the idea?
You will also need this compiler argument so the HTTPService doesnt look online for the xml
-locale en_US -use-network=false
You could not bother with dowloading the file in the firstplace and just embed it in the Application
here a link to the topic

Why does URLStream complete event get dispatched when the file is not finished loading?

I'm writing an AIR kiosk app that every night connects to a WordPress server, gets a JSON file with paths to all the content, and then downloads that content and saves it to the kiosk hard drive.
There's several hundred files (jpg, png, f4v, xml) and most of them download/save with no problems. However, there are two f4v files that never get downloaded completely. The complete event does get dispatched, but if I compare the bytesTotal (from the progress event) vs bytesAvailable (from the complete event) they don't match up; bytesTotal is larger. The bytesTotal (from the progress event) matches the bytes on the server.
The bytesLoaded in the progress event never increases to the point that it matches the bytesTotal either so I can't rely on the progress event either. This seems to happen on the same two videos every time. The videos are not very large, one is 13MB and the other is 46MB. I have larger videos that download without any problems.
EDIT: After rebooting my computer, the two videos now finish downloading but I'm getting the same problem with a 300kb png file.
If I paste the url into Firefox it downloads correctly. I've also written a simple c# app to download the files and it is able to download them with no problems, so it appears to be a problem with Flash/AIR.
EDIT: here's a simpler version of the code, this is from a test project and it's the only code (the url is on our local network so you won't be able to download the file yourself):
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
import flash.net.URLStream;
[SWF(backgroundColor="#000000", frameRate="24", width="640", height="480")]
public class Test extends Sprite {
private var fileSize:Number;
private var stream : URLStream;
private var url:String = "http://192.168.150.219/wordpress2/wp-content/uploads/2012/12/John-Butler-clip1.f4v";
public function Test() {
if (stage)
init();
else
this.addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event=null):void {
this.removeEventListener(Event.ADDED_TO_STAGE, init);
stream = new URLStream();
stream.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
stream.addEventListener(Event.COMPLETE, onLoadComplete);
stream.load(new URLRequest(url));
}
private function onLoadProgress(event:ProgressEvent):void {
fileSize = event.bytesTotal;
var percent:Number = event.bytesLoaded / event.bytesTotal * 100;
trace(percent + "%"); // this never gets to 100%
}
private function onLoadComplete(event:Event):void {
trace("loaded", stream.bytesAvailable, "of", fileSize);
// outputs "loaded 13182905 of 13184365"
// so why is it "complete" when it isn't fully downloaded?
}
}
}
Don't compare to bytesAvailable, use length instead. BytesAvailable is actually ByteArray.length - ByteArray.position. So if the position within the ByteArray has moved away from index 0, the bytesAvailable value will decrease. Length will always be the total number of bytes within the array.
Try comparing using length and see if this makes any difference. I don't have time to sift through your code to see if you are changing position at any point (either purposefully or accidentally; you can do it in more ways than one), so that's the best I can offer right now.
If anyone else has the same problem like I did. It turned out to be a caching problem which is present in AIR as well so a timestamp added to the request solves this: http://www.newtonflash.com/blog/as3/prevent-xml-caching-problem/#comment-43
{
var xmlPath:String="replaceYourXMLPathHere.xml"
var urlReq:URLRequest = new URLRequest(xmlPath+"?time=" + new Date().getTime());
}
Your answer is in your question.
Normal URLs (files) - to this server this is a block of data. Once the server delivers the 'block of data' the delivery process is considered 'COMPLETE'. In this case if a file is 100kb, once the 100kb is received - Flash considers this as 'COMPLETE'.
URLStream - to the server this is [TWO] blocks of data (very simple way to look at it). The server will first serve the CONNECTION to the stream... then serve the STREAM DATA. This is handled in Flash just as its described.
Flash will consider the loading of the CONNECTION as 'COMPLETE', and NEVER check if the STREAM data is loaded - thats up to your server. In any streams you should actually check the [load progress] event and read each byte of data as it comes in... then construct as required.

Flash AS3 : Error #1014 : When loading remotely but not locally

Starting with a blank project, when I load a SWF which has a dependence on ISomeInterface defined in a swc which is compiled into my blank project
var lc:LoaderContext = new LoaderContext( true, ApplicationDomain.currentDomain );
var loader:Loader = new Loader();
loader.load( new URLRequest( "Some.swf"), lc );
Not too surpisingly all is good as the interface it requires is already in the application domain into which it has been loaded.
However, when I load the same file from a remote url
loader.load( new URLRequest( "http://127.0.0.1/Some.swf"), lc );
I get the evil
[Fault] exception, information=VerifyError: Error #1014: Class ISomeInterface could
not be found
What am I missing that makes these different?
My issue appears to have been 2 fold
1) When loading the asset locally, it will by default be loaded into the correct security domain. However, when loading from a web site, I need ensure that I set the security domain correctly
new LoaderContext( true, ApplicationDomain.currentDomain, SecurityDomain.currentDomain )
2) However, you can only use the SecurityDomain when the swf you are doing the loading from was actually itself loaded remotely :
Security.sandboxType == Security.REMOTE
So no mix mode of local and remote.
In the end it was a matter of simply loading the first SWF from a website, and adding the correct SecurityDomain.
In my searching, this was the best discorse I found on the topic of Security Domains and Applciation Domains http://www.senocular.com/flash/tutorials/contentdomains/
Since your testing locally you might want to check this out:
http://jansensan.net/flash-player-security-settings-to-develop-locally
Essentially go to the Flash Player security page:
http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html
Click Edit Location -> Add location
Add the project folder or your filesystem root.