I'm trying to load data from a website in my AS3 program. However, urlLoader.load() never finishes, yet the program runs without any errors.
Here's my code:
Main.as:
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.net.URLRequestMethod;
import ttTextField;
public class Main extends Sprite
{
private var textField:ttTextField = new ttTextField("", false);
public function Main():void
{
var urlRequest:URLRequest = new URLRequest("http://itch.io/api/1/API_KEY_REMOVED_FOR_SECURITY/my-games");
urlRequest.method = URLRequestMethod.GET;
var urlLoader:URLLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.TEXT;
urlLoader.addEventListener(Event.COMPLETE, completeHandler);
urlLoader.load(urlRequest);
stage.addChild(textField);
}
private function completeHandler(event:Event):void
{
textField.text = event.target.data;
}
}
ttTextField.as:
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormatAlign;
import flash.text.TextFormat;
public class ttTextField extends TextField
{
[Embed(source = "../files/Fixedsys500c.ttf", embedAsCFF = "false", fontName = "fixedSys")] private var fontClass:Class;
private var textFormat:TextFormat = new TextFormat("fixedSys", 24);
public function ttTextField(string:String, centered:Boolean)
{
if (centered)
{
textFormat.align = TextFormatAlign.CENTER;
}
else
{
textFormat.align = TextFormatAlign.LEFT;
}
string = string;
this.autoSize = TextFieldAutoSize.LEFT;
this.mouseEnabled = false;
this.embedFonts = true;
this.textColor = 0xFFFFFF;
this.defaultTextFormat = textFormat;
this.text = string;
}
}
ttTextField can display regular strings, so it doesn't seem like this class is the issue. I just included it for completion's sake.
I'm also building and running using Sublime Text 2. My sublime-build file is as follows:
{
"cmd": ["C:\\Users\\Dan\\Documents\\flex_sdk_4.6\\bin\\mxmlc.exe", "-output=C:\\Users\\Dan\\TTTT\\TTTT.swf", "-default-background-color=#00FF00", "-default-size=800,600", "C:\\Users\\Dan\\TTTT\\src\\Main.as", "-static-link-runtime-shared-libraries=true"],
"file_regex": "(.*)[(](\\d+)[)]:(?: col: (?:\\d+))? *Error: (.*)",
"selector": "source.actionscript",
"variants":
[
{
"name": "Run",
"shell": true,
"cmd": ["C:\\Users\\Dan\\TTTT\\TTTT.swf"]
}
]
}
I've tried running the program in both Flash Player and Google Chrome. Every time the output is just a blank screen.
How would I get my URLLoader to actually load the URL? I can provide more information if needed. Thank you for reading.
I think that simply your Main class should extend from MovieClip and not Sprite :
public class Main extends MovieClip
{
// ...
}
And to debug your project in the browser, you can use a flash player debug version which you can download from here.
Hope that can help.
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
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);
I've been struggling with a Flash preloader. I just want it to update the text on the screen with the current percentage. Now it basically works as the trace outputs the correct percentages, but it won't update the textfield I have on the screen. Once the trace gets to 100% however, the code does output "100" on the screen, but not until it's all loaded. I don't have the Flash IDE and am just using pure Actionscript with FlashDevelop. Here's my code:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.display.Loader;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
import flash.net.URLLoader;
import flash.display.Loader;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldType;
public class Main extends Sprite
{
public var myLoader:Loader = new Loader();
public var image:String = "tmp/Avengers-poster.jpg";
private var Title:TextField;
private var txt:String;
private var Form:TextField;
public function Main():void {
textbox("This is the title","box",100,100,200,30);
myLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressStatus);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderReady);
var fileRequest:URLRequest = new URLRequest(image);
myLoader.load(fileRequest);
}
public function onProgressStatus(e:ProgressEvent):void {
// this is where progress will be monitored
var perc:int = Math.ceil((e.bytesLoaded/e.bytesTotal)*100);
txt = perc.toString();
Title.text = txt;
addChild (Title);
trace(perc);
}
public function onLoaderReady(e:Event):void {
// the image is now loaded, so let's add it to the display tree!
addChild(myLoader);
}
private function textbox (title_str:String,form_name:String,x:int,y:int,width:int,height:int):void {
Title = new TextField ();
Title.text = title_str;
Title.selectable = false;
Title.setTextFormat (new TextFormat ("Arial", 12, 0x777777, true));
txt = ".";
Title.x = x;
Title.y = y;
addChild (Title);
}
}
}
Thanks for your help.
Darryl
This will work. Don't recreate the TextField on each status. You only need to addChild once and update the reference to it.
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
public class Main extends Sprite
{
public var myLoader:Loader = new Loader();
public var image:String = "http://apod.nasa.gov/apod/image/0605/titan5km_huygens_big.jpg";
private var Title:TextField;
private var Form:TextField;
public function Main():void {
createTextField("This is the title","box",100,100,200,30);
myLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressStatus);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderReady);
var fileRequest:URLRequest = new URLRequest(image);
myLoader.load(fileRequest);
}
public function onProgressStatus(e:ProgressEvent):void {
// this is where progress will be monitored
var perc:int = Math.ceil((e.bytesLoaded/e.bytesTotal)*100);
Title.text = perc.toString();
}
public function onLoaderReady(e:Event):void {
// the image is now loaded, so let's add it to the display tree!
addChild(myLoader);
}
private function createTextField (title_str:String,form_name:String,x:int,y:int,width:int,height:int):void {
Title = new TextField();
Title.text = title_str;
Title.selectable = false;
Title.setTextFormat (new TextFormat ("Arial", 12, 0x777777, true));
Title.text = ".";
Title.x = x;
Title.y = y;
addChild (Title);
}
}
}
I've searched high and low for a fix to this issue, but cannot find ANYTHING on why almost all the properties are being returned as 0.
I am using FLV wrapping to pull a live audio stream from Icecast (since Adobe, 15 years later, still haven't fixed their live audio memory leak issue). It works great, everything functions perfectly.
However, I'm wanting to create a bandwidth monitor (for my iPhone port, and for my normal Flash player)... But whenever I retrieve netStreamInfo it returns as 0! For dataBytesPerSecond, audioBytesPerSecond, byteCount, dataByteCount, nearly EVERY SINGLE PROPERTY returns 0. I have this run on a 1-second timer.
Here's the total info output:
currentBytesPerSecond=0
byteCount=0
maxBytesPerSecond=0
audioBytesPerSecond=0
audioByteCount=0
videoBytesPerSecond=0
videoByteCount=0
dataBytesPerSecond=0
dataByteCount=0
playbackBytesPerSecond=16296.296296296296
droppedFrames=0
audioBufferLength=0.072
videoBufferLength=0
dataBufferLength=0
audioBufferByteLength=1540
videoBufferByteLength=0
dataBufferByteLength=0
srtt=0
audioLossRate=0
videoLossRate=0 Data Bytes Per Second
That output was about 5 minutes in. I noted the playBackBytesPerSecond never changed, and the audioBufferByteLength liked to switch between 1540 and 23xx randomly.
Can anyone pleaaase help me out here?
My actionscript:
package
{
import flash.display.Sprite;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.text.TextFieldAutoSize;
import flash.text.TextField;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.events.NetStatusEvent;
import flash.utils.Timer;
import flash.media.Sound;
import flash.net.URLRequest;
import flash.media.SoundChannel;
import flash.media.SoundMixer;
import flash.media.SoundTransform;
import flash.display.Loader;
import flash.errors.IOError;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.net.NetStreamInfo;
import flash.utils.ByteArray;
import flash.media.*
public class soundContainer extends Sprite
{
public var slider:SliderMC = new SliderMC();
private var _video:Video;
private var _stream:NetStream;
private var _playbackTime:TextField;
private var _duration:uint;
private var _timer:Timer;
private var _soundChannel:SoundChannel;
public var audioTransform:SoundTransform = new SoundTransform();
public var _URL:String;
public var flvUrl:String = "s";
public var dragging:Boolean = false;
public var rectangle:Rectangle = new Rectangle(0,0,100,0);
private var ba:ByteArray;
private var bn;
public function soundContainer() {
addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event):void
{
ba = new ByteArray();
slider.x = 73.85;
slider.y = 10.95;
addChild(slider);
slider.slider_mc.addEventListener(MouseEvent.MOUSE_DOWN, dragIt);
stage.addEventListener(MouseEvent.MOUSE_UP, dropIt);
_timer = new Timer(1000);
_timer.addEventListener(TimerEvent.TIMER, onTimer);
_timer.start();
}
public function dragIt(e:MouseEvent):void
{
slider.slider_mc.startDrag(false, rectangle);
dragging = true;
slider.slider_mc.addEventListener(Event.ENTER_FRAME, adjustVolume);
}
public function dropIt(e:MouseEvent = null):void
{
if (dragging)
{
slider.slider_mc.stopDrag();
dragging = false;
}
}
public function adjustVolume(e:Event):void
{
var vol:Number = slider.slider_mc.x / 100;
var st:SoundTransform = new SoundTransform(vol);
SoundMixer.soundTransform = st;
}
public function playMyFlv(flvUrl)
{
_URL = flvUrl;
_video = new Video();
var connection:NetConnection = new NetConnection();
connection.connect(null);
_stream = new NetStream(connection);
_stream.soundTransform = audioTransform;
_stream.play(flvUrl);
var Client:Object = new Object();
_stream.client = Client;
_video.attachNetStream(_stream);
addChild(_video);
}
public function stopMyFlv()
{
SoundMixer.stopAll();
trace("stop");
try
{
_stream.close();
}
catch (error:IOError)
{
}
}
private function onNetStatus(e:NetStatusEvent)
{
}
private function onTimer(t:TimerEvent):Number
{
trace(_stream.info + " Data Bytes Per Second");
}
public function onIOError(e:IOError)
{
trace("Failed to load");
}
}
}
In a plugin context (a swf loaded by an another swf), is there any way to restrict access to file system and network in the same time to the loaded swf ?
Compiler option "-use-network=true|false" does not fit because you cannot restrict both file/network.
Code example :
Air App :
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.filesystem.File;
import flash.net.URLRequest;
public class TestContentSecurity extends Sprite
{
private var l :Loader = new Loader;
public function TestContentSecurity()
{
addChild(l);
l.load(new URLRequest(File.documentsDirectory.nativePath + "/Content.swf"));
}
}
}
Loaded swf :
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.text.TextField;
public class Content extends Sprite
{
private var _log : TextField = new TextField;
private var l: URLLoader;
public function Content()
{
addChild(_log)
_log.multiline = true;
_log.width = 500;
_log.height = 500;
l = new URLLoader();
l.addEventListener(Event.COMPLETE, onLoad);
l.addEventListener(IOErrorEvent.IO_ERROR, onError);
l.load(new URLRequest("c:/Windows/regedit.exe"))
}
public function onLoad(e:Event) : void{
_log.text += "SUCCESS\n" ;
}
public function onError(e:IOErrorEvent) : void{
_log.text += "ERROR\n";
}
}
}
The loaded swf is in user's document folder, outside Air app folder. Currently, the loaded swf is abble to load "c:/Windows/regedit.exe" and I don't want it (neither sending informations on the network).
I've found one solution in AIR, I don't like it but it works. The idea is to have a mini http server and to load content from this server.
I load targeted file with :
new URLRequest("http://localhost:1111/Content.swf")
By doing this, flash will load "Content.swf" as a remote file and place it in a REMOTE security sandbox. Loaded swf won't be able to access to any local files neither to network.
If anyone have a cleaner solution to get this REMOTE security sand box, I will be happy.
/**
* HTTP server original idea :
* http://coenraets.org/blog/2009/12/air-2-0-web-server-using-the-new-server-socket-api/
*/
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.net.URLRequest;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.events.ServerSocketConnectEvent;
import flash.net.ServerSocket;
import flash.net.Socket;
import flash.utils.ByteArray;
public class TestContentSecurity extends Sprite
{
private var l :Loader = new Loader;
private var serverSocket:ServerSocket;
public function TestContentSecurity()
{
init();
l.load(new URLRequest("http://localhost:1111/Content.swf"));
}
private function init():void
{
// Initialize the web server directory (in applicationStorageDirectory) with sample files
listen(1111);
}
private function listen(port : uint):void
{
try
{
serverSocket = new ServerSocket();
serverSocket.addEventListener(Event.CONNECT, socketConnectHandler);
serverSocket.bind(port, "127.0.0.1");
serverSocket.listen();
trace("Listening on port " + port + "...\n");
}
catch (error:Error)
{
trace("Port " + port +
" may be in use. Enter another port number and try again.\n(" +
error.message +")", "Error");
}
}
private function socketConnectHandler(event:ServerSocketConnectEvent):void
{
var socket:Socket = event.socket;
socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
}
private function socketDataHandler(event:ProgressEvent):void
{
try
{
var socket:Socket = event.target as Socket;
var bytes:ByteArray = new ByteArray();
socket.readBytes(bytes);
var request:String = "" + bytes;
var filePath:String = request.substring(5, request.indexOf("HTTP/") - 1);
var file:File = File.applicationDirectory.resolvePath(filePath);
if (file.exists && !file.isDirectory)
{
var stream:FileStream = new FileStream();
stream.open( file, FileMode.READ );
var content:ByteArray = new ByteArray();
stream.readBytes(content);
stream.close();
socket.writeUTFBytes("HTTP/1.1 200 OK\n");
socket.writeUTFBytes("Content-Type: application/x-shockwave-flash\n\n");
socket.writeBytes(content);
}
else
{
socket.writeUTFBytes("HTTP/1.1 404 Not Found\n");
socket.writeUTFBytes("Content-Type: text/html\n\n");
socket.writeUTFBytes("<html><body><h2>Page Not Found</h2></body></html>");
}
socket.flush();
socket.close();
}
catch (error:Error)
{
trace("Error");
}
}
}
}
Not unless you deploy as an AIR application.
You can, however, store some data in a SharedObject, even when you deploy with -use-network=true. This should work for storing game state and such.
Edit:
In AIR, security between content from different domains is regulated by using AIR sandbox bridges. This should give you all the leverage you need.