I hope I can get some help with my actionscript problem.
(inb4: 'What exactly are you trying to accomplish (other than opening an arbitrary file without user permission)?' link)
I am trying to assist with student exercises - so I thought I'd come up with an example of a random gallery. The idea with this would be that students would be able to generate a SWF file, and in the same directory, they would have a folder with images. Then the SWF movie would read the contents of the directory; choose a random image, and display it.
I would have hoped that this could be done both locally (while students develop) - and, should they choose so, they should be able to upload the entire directory online -- and hopefully, the example would work either way. That turns out not to be so easy - so these are my questions:
They say, that in order to get local directory listing, I should use AIR - what does that mean? Is there some executable - other than flashplayerdebugger - that I should call in order to reproduce the SWF if it uses AIR?
Is it possible to get a local directory listing without using this AIR (in the similar vein as the Flex code below?)
It seems I can load a local text file; but I cannot load a local bitmap file. Would it be possible to load a bitmap file as well?
How can you give local access permission to files/folders, if it so happens that you don't have access to the Internet, so you cannot access settings_manager04.html - but you'd like to use a Flash application both with local files and with network sockets on the local network?
Now, one thing is that most students work with Flash CSx versions - I on the other hand am on Linux, so I have tried to make a Flex example; so I've provided the example as Flex code, but I'd like to know possible answers for the Flash CS environment too. The directory structure, compile lines, and code is given at end of this post - but here is how the "application" directory looks like:
Ok, so here is the problem in a bit more detail. First, I thought I'd try to read the directory contents - so I tried the code here: AS3 Basics: List all files in a folder including subdirectories (AIR ... on students' Flash CS - but that seemed to fail miserably.
So I thought - OK, then let's put in a text file in the same directory as the .swf, which will contain a list of the images; e.g.
cat > fileslist.txt <<EOF
img/01.jpg
img/02.jpg
EOF
Then, the Flash app would read this file first - and then proceed to choose a random image from the contents. But at the very first instant, I get:
An ActionScript error has occurred:
SecurityError: Error #2148: SWF file file:///home/rgaltest/rgaltest.swf cannot access local resource file:///home/rgaltest/fileslist.txt. Only local-with-filesystem and trusted local SWF files may access local resources.
at flash.net::URLStream/load()
at flash.net::URLLoader/load()
at rgaltest()[/home/rgaltest/rgaltest.as:23]
So, the answer to this seems to be:
"If you are getting that error when using flash.net.URLLoader and the free flex compiler, add the following option when you compile to get your swf to work: -use-network=false" (juicy tidbits - Only local-with-filesystem and trusted local SWF files may access local resources.)
"Turns out the solution is to configure your Flash Player to trust the swfs in the project’s /bin-debug directory ... 1) Goto http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html ... " (Solution – Error #2010: Local-with-filesystem SWF files are not permitted to use sockets. » Mark Lapasa)
Now, I would not like to have -use-network=false - because students may need to integrate other network based stuff in that example. Then again, something similar to that "settings_manager04.html" ("Global Security Settings panel") page shows up if you open the SWF in a browser, then right-click, then choose "Global Settings" - but does it work for SWF files being shown as a part of Ctrl-Enter build in Flash CS (or correspondingly, those that are open with flashplayerdebugger?) So I try it - choose "Edit Locations", "Browse for folder", choose /home/rgaltest under "Always Allow":
... and now the fileslist.txt gets loaded alright; also when the .swf is ran with flashplayerdebugger.
Right, so now that the files list is loaded, I'd proceed on loading the bitmaps.. so I add the respective code (with onImgLoaded etc), and this is what I get in the log:
At frame #1
file onTextLoaded: img/01.jpg,img/02.jpg,
At frame #2
file onImgLoaded: [object URLLoader]
TypeError: Error #1034: Type Coercion failed: cannot convert "ÿØÿà
...
¿ÿÙ" to flash.display.Bitmap.
at rgaltest/onImgLoaded()[/home/rgaltest/rgaltest.as:64]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at flash.net::URLLoader/onComplete()
At frame #3
At frame #4
...
Interestingly - the image did get read - as all of its binary contents are dumped to the log! Yet, it cannot be interpreted as bitmap data???!
First of all, this is my directory layout:
mkdir /home/rgaltest
cd /home/rgaltest
touch rgaltest.as
touch fileslist.txt
mkdir img
cd img
convert -size 320x240 gradient:\#4b4-\#bfb 01.jpg
convert -size 320x240 gradient:\#b44-\#bff 02.jpg
chmod -R 777 /home/rgaltest # to ensure no problem with file permissions
The rgaltest.as is given below; I compile that with:
/path/to/flex_sdk_4.6.0.23201_mpl/bin/mxmlc -static-link-runtime-shared-libraries -use-network=true -verbose-stacktraces -debug=true rgaltest.as
... and I check that locally with (make sure mm.cfg is properly set up, see also Using Flash Player debugger):
# in one terminal:
tail -f ~/.macromedia/Flash_Player/Logs/flashlog.txt
# in another terminal:
/path/to/flashplayer_11/flashplayerdebugger rgaltest.swf
And finally, here is rgaltest.as:
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.IEventDispatcher;
import flash.net.*; //URLLoader;
import flash.display.Bitmap;
import flash.display.BitmapData;
[SWF(width="550", height="400")]
public class rgaltest extends MovieClip {
public var _pictureArray:Array;
public var frameCnt:Number = 0;
public var myTextLoader:URLLoader;
public var isFileslistLoaded:Boolean = false;
public var myImgLoader:URLLoader;
public var isImgLoading:Boolean = false;
// constructor - create/initialize objects here
public function rgaltest() {
this.stage.frameRate = 10; // frames per second
// load the text file with image list
myTextLoader = new URLLoader();
myTextLoader.addEventListener(Event.COMPLETE, onTextLoaded);
myTextLoader.load(new URLRequest("fileslist.txt"));
// add event listener for onEnterFrame
configureListeners(this);
}
private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.ENTER_FRAME, my_OnEnterFrame);
}
public function onTextLoaded(e:Event):void {
_pictureArray = e.target.data.split(/\n/);
trace("file onTextLoaded: " + _pictureArray);
isFileslistLoaded = true;
}
public function my_OnEnterFrame(event:Event):void {
frameCnt++;
trace("At frame #" + frameCnt);
if (isFileslistLoaded) {
if (!isImgLoading) {
//load a random image
var rndChoice:Number = Math.floor(Math.random()*2) + 1;
myImgLoader = new URLLoader();
myImgLoader.addEventListener(Event.COMPLETE, onImgLoaded);
myImgLoader.load(new URLRequest(_pictureArray[rndChoice]));
isImgLoading = true;
}
}
} // end onEnterFrame
public function onImgLoaded(e:Event):void {
trace("file onImgLoaded: " + e.target);
var _image:Bitmap = Bitmap(e.target.data);
var _bitmap:BitmapData = _image.bitmapData;
addChild(_image);
}
} //end class
} //end package
Some other relevant links:
flex - Adding Local Filenames/References To Array In Actionscript - Stack Overflow
flash - Is there a way to read local files in ActionScript 3 "silently"'? - Stack Overflow
adobe flash cs4 as3: get current directory of a running project? - Stack Overflow
flex - open local files in AS3 - Stack Overflow
Bump - it seems I solved the bitmap loading (putting it here in separate post, so that I don't clog the OP too much); I just used Loader class instead of URLLoader; see code below (also note the mistake in random calculation in OP, which is corrected below).
Anyways - this is the thing: when I tried the Loader class on the students' Flash CSx, it tended to fail miserably! But, maybe that was because in those cases, we didn't give any permissions to the folder from "settings_manager04.html"? Any special things that should be taken care of, when a code similar to this is generated in Flash?
Here is the reworked rgaltest.as:
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.IEventDispatcher;
import flash.net.*; //URLLoader;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader; //*
[SWF(width="550", height="400")]
public class rgaltest extends MovieClip {
public var _pictureArray:Array;
public var frameCnt:Number = 0;
public var myTextLoader:URLLoader;
public var isFileslistLoaded:Boolean = false;
public var myImgLoader:Loader;
public var isImgLoading:Boolean = false;
// constructor - create/initialize objects here
public function rgaltest() {
this.stage.frameRate = 10; // frames per second
// load the text file with image list
myTextLoader = new URLLoader();
myTextLoader.addEventListener(Event.COMPLETE, onTextLoaded);
myTextLoader.load(new URLRequest("fileslist.txt"));
// add event listener for onEnterFrame
configureListeners(this);
}
private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.ENTER_FRAME, my_OnEnterFrame);
}
public function onTextLoaded(e:Event):void {
_pictureArray = e.target.data.split(/\n/);
trace("file onTextLoaded: " + _pictureArray);
isFileslistLoaded = true;
}
public function my_OnEnterFrame(event:Event):void {
frameCnt++;
trace("At frame #" + frameCnt);
if (isFileslistLoaded) {
if (!isImgLoading) {
//load a random image
var rndChoice:Number = Math.floor(Math.random()*2) + 0;
trace("Loading: " + rndChoice + " / " + _pictureArray[rndChoice]);
myImgLoader = new Loader();
myImgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImgLoaded);
myImgLoader.load(new URLRequest(_pictureArray[rndChoice]));
isImgLoading = true;
}
}
} // end onEnterFrame
public function onImgLoaded(e:Event):void {
trace("file onImgLoaded: " + e.target);
var _image:Bitmap = Bitmap(myImgLoader.content);
var _bitmap:BitmapData = _image.bitmapData;
addChild(_image);
}
} //end class
} //end package
Related
Is there any way to save the objects that are currently on the stage in Flash?
For example, if the user drags a particular MovieClip from a panel that is part of the interface and places it somewhere on the stage and then adds a TextField by clicking a Button.
Is there any way to save the location, properties and various other things to an external file?
So that, if the user were to click a 'load' button, it would load the MovieClip and text back onto the blank stage when the program is next run and they'd be in the exact same position?
Yes, You can save this information in XML file for example.
Sample of XML might be like so,
WorkSpace.xml
<stageObjects>
<object libName="myTextField" type="TextField" xPos="20" yPos"10" txt="SomeText" />
<object libName="myMovieClip" type="MovieClip" xPos="20" yPos"10" />
</stageObjects>
On your app load, read this XML file and take the required actions.
If I had any type of local client-level game and I was using flash to save local values for the same purposes a cookie may have; I would utilize the SharedObject Class. It is not a traditional mime type, it also has a .sfo extension and they are usually stored in a random directory..So they are only cleared when the user Flushes their "Regular" Browsing Data. Without getting overly complicated, this demo will allow you to save data, close the SWF file, re-open it and find the last setting.
package {
import flash.display...
import flash.events...
import flash.events.NetStatusEvent;
import flash.net.SharedObject;
import flash.net.SharedObjectFlushStatus;
import flash.text.TextField;
import flash.text...
public class SharedObjectClass {
private var _so:SharedObject;
private var _in:TextField = new TextField();
public function SharedObjectClass() {
_so = SharedObject.getLocal("application-name");
addChild(_in.text = String(_so.data.savedValue));
}
private function saveValue(event:*=null):void {
_so.data.savedValue = _in.text;
var flushStatus:String = null;
try {
flushStatus = _so.flush(10000);
} catch (error:Error)
//..nothing?
}
if(flushStatus != null) {
if(flushStatus == SharedObjectFlushStatus.PENDING) {
_so.addEventListener(NetStatusEvent.NET_STATUS, onFlushStatus);
}
}
}
private function clearValue(event:*=null):void {
delete _so.data.savedValue;
}
private function onFlushStatus(event:NetStatusEvent):void {
switch (event.info.code) {
case "SharedObject.Flush.Success":
break;
case "SharedObject.Flush.Failed":
break;
}
_so.removeEventListener(NetStatusEvent.NET_STATUS, onFlushStatus);
}
}
}
The Value _co will always be your reference to this object, renaming it will create a new instance. I have taken these files apart and they are well written XML files that accommodate to AMF For Servers. In this example "Saving", "Clearing", and "Flushing Methods" are described in simple detail.
Greatings!
I have yet another question concerning the loading of a .swf inside a existing one.
In my game. I have a introduction screen in which I load another .swf (which is a movie).
This all works fine and the URLRequest is this:
request = new URLRequest("Movie.swf");
As I said, this works fine. However when I copy my game.swf and movie.swf to a USB stick.
(I put them in the same directory to prevent other issues).
It doesn't seem to find the movie.swf.
Now I know that it has to do with the path given in the URLRequest and/or the publish settings. But I do not know how to make this so that it searches in the same directory
as the game.swf is in.
I hope you guys have an answer for this issue.
Thanks in advance,
Matti.
Matti, I believe Lukasz's comment is correct about it being a security error.
You can avoid this security error by embedding Movie.swf instead of using a Loader. If you do this, then at compile-time the Movie.swf needs to sit next to the Game.as file, and it will be included in the Game.swf (no need to deliver both files, just Game.swf).
The syntax is:
package
{
import flash.display.Sprite;
public class Game extends Sprite
{
[Embed(source="MyMovie.swf")]
private var myMovieClass:Class;
private var myMovie:DisplayObject;
public function Game():void
{
myMovie = new myMovieClass();
// Technically myMovie is now a Loader, and once
// it's loaded, it'll have .content that's a
// MovieClipLoaderAsset, and .content.getChildAt(0)
// will be your MyMovie.swf main timeline.
}
}
}
Alternately, if you embed it as mimeType="application/octet-stream", you can get the bytes of the SWF and use it in your existing Loader's .loadBytes() method:
package
{
import flash.display.Sprite;
import flash.utils.ByteArray;
public class Game extends Sprite
{
[Embed(source="MyMovie.swf", mimeType="application/octet-stream")]
private var movieBytes:Class;
private var myMovie:DisplayObject;
public function Game():void
{
// Treat this loader the same as your current loader,
// but don't call .load(url), call loadbytes():
var l:Loader = new Loader();
l.loadBytes(new movieBytes() as ByteArray);
}
}
}
I am very new in AS3. I use FlashDevelop 4. I have no Adobe Flash, just FD (pure AS3) I have problems with classpath. I searched the database but I found nothing that could help me. So the problem is as follow.
I have the project "Testing" in C:\AS App\Testing with the file Main.as. I have, also, the folder C:\AS App\W_T. In this folder is the file write_text.as. The file Main.as looks like that:
package
{
import flash.display.*;
import flash.text.TextField;
import flash.events.*;
import W_T.write_text;
public class Main extends Sprite
{
var t:TextField=new TextField();
public function Main():void
{
stage.addChild(t);
stage.addEventListener(MouseEvent.CLICK, write);
}
public function write(me:MouseEvent):void
{
var wt:W_T.write_text = new W_T.write_text();
t.x = 100;
t.y = 100;
t.text = wt.output();
}
}
}
The file write_text.as looks like that:
package W_T
{
import flash.display.*;
import flash.text.TextField;
import flash.events.*;
import W_T.*;
public class write_text
{
public function write_text()
{
}
public function output():String
{
var txt:String;
txt = "From function !";
return(txt);
}
}
}
I make the appropriate specification in the global classpath. But I get the following errors:
Error: Type was not found or was not a compile-time constant: write_text.
var wt:W_T.write_text = new W_T.write_text();
Error: Call to a possibly undefined method write_text.
var wt:W_T.write_text = new W_T.write_text();
Definition W_T:write_text could not be found.
import W_T.write_text;
Could you help me please to find where I have done wrong ?
Thank you.
EB
The problem is the compiler isn't finding your write_text.as file. By default, it will be looking here:
C:\AS App\Testing\W_T\write_text.as
Try adjusting accordingly and see if it works. When you declare package W_T { } flash will look in a subfolder called W_T for a file with the same name as the public class.
When you declare just simply package { } with no name, it will look in the root of your class library path, which seems to be a folder called Testing if that's where your main.as file is living.
If you wanted to use a common folder for your class files (that isn't nested in an individual projects folder), you can tell flash develop where to find them by going to: project -> properties, then the Classpaths tab. By default flash develop will only look in folders relative to the project.
The problem is that you haven't told the compiler (flex?) where to find the file. When you add it as classpath you only tell flash develop where to find the file, not the compiler.
First of all you have to check how you compile and secondly how you can change and add classpaths for your solution.u
I usually do this through ant script and a build.xml file and I can't unfortunately remember how the "pure as3"-projects are working in regards to compiling
I'm trying to play a remote AAC file in ActionScript 3 in Flash CS3 and am currently using this code:
var url:String = "http://a1.phobos.apple.com/us/r1000/020/Music/d4/50/94/mzm.kjjofihr.aac.p.m4a";
var connect_nc:NetConnection = new NetConnection();
connect_nc.connect(null);
var stream_ns:NetStream = new NetStream(connect_nc);
stream_ns.play(url);
(This is based on: http://www.adobe.com/devnet/flashplayer/articles/hd_video_flash_player_03.html)
No errors are thrown, but no sound is played. I get the same behavior with a local AAC file and with a local MP4 video.
If I use a URL or file path that isn't a streamable file, I get a NetStream.Play.StreamNotFound error, which I'm guessing means that the stream is found in the case of a valid URL. If I use a local FLV, its audio is played just fine.
If I add the following listener and trace(evt.info.code) in netStatusHandler, I only see any codes (e.g. NetStream.Play.Start) traced with the FLV. No codes are traced with the AAC or MP4.
stream_ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
The same is true of adding this listener (i.e. the onMetaData argument is only traced with the FLV, not with the other file types), with metaDataListener defined as an object with an onMetaData method that traces its argument.
stream_ns.client = metaDataListener;
Any ideas of what might be going wrong here, or how to diagnose it?
Thanks!
As stated here http://www.adobe.com/devnet/flashplayer/articles/hd_video_flash_player_03.html what you are doing is correct.
var connect_nc:NetConnection = new NetConnection();
connect_nc.connect(null);
var stream_ns:NetStream = new NetStream(connect_nc);
stream_ns.play("RE-Sample.m4a");
However, the Actionscript Language reference about nestream found here:
http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/net/NetStream.html#play%28%29
states that:
play () method
...
...
When you use this method without Flash Media Server, there are security considerations. A file in the local-trusted or local-with-networking sandbox can load and play a video file from the remote sandbox, but cannot access the remote file's data without explicit permission in the form of a cross-domain policy file. Also, you can prevent a SWF file running in Flash Player from using this method by setting the allowNetworking parameter of the the object and embed tags in the HTML page that contains the SWF content.
...
...
Parameters
... arguments — The location of the video file to play, as a URLRequest object or a string. In Flash Player and in AIR content outside of the application security sandbox, you can play local video files that are stored in the same directory as the SWF file or in a subdirectory; however, you can't navigate to a higher-level directory.
So it's probably a security sandbox issue.
Everything in ActionScript 3.0 is event based (with few random exceptions where callbacks are used).
You need to listen for the NetStatusEvent with info.code "NetConnection.Connect.Success" in order to be allowed to call the NetStream.play() function.
Here's something that works (I just wrote it now, and tested it for you):
package
{
import flash.display.Sprite;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.events.NetStatusEvent;
import flash.events.AsyncErrorEvent;
import flash.events.Event;
public class MainDocument extends Sprite
{
private var _connection:NetConnection=new NetConnection();
private var _netStream:NetStream=null;
private var _strM4AURL:String="http://a1.phobos.apple.com/us/r1000/020/Music/d4/50/94/mzm.kjjofihr.aac.p.m4a";
//constructor
public function MainDocument():void
{
this._connect();
}
private function _connect():void
{
this._connection.close();
this._connection=new NetConnection();
this._connection.addEventListener(NetStatusEvent.NET_STATUS, this._netStatusHandler);
this._connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, this._asyncErrorHandler);
this._connection.connect(null);
}
private function _netStatusHandler(event:NetStatusEvent):void
{
trace(event.info.code);
switch (event.info.code)
{
case "NetConnection.Connect.Success":
this._requestAudio();
break;
}
}
private function _requestAudio():void
{
if(this._netStream!==null)
this._netStream.close();
this._netStream=new NetStream(this._connection);
this._netStream.addEventListener(NetStatusEvent.NET_STATUS, this._netStatusHandler);
this._netStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, this._asyncErrorHandler);
this._netStream.checkPolicyFile=false;
this._netStream.play(this._strM4AURL);
}
private function _asyncErrorHandler(event:AsyncErrorEvent):void
{
trace(event);
}
}
}
Consult the ActionScript 3.0 Language Reference for more information.
There's a good chance what Oliver is saying is true as your not getting any feedback from any event listeners associated with the NetStream, and you are getting a StreamNotFound response.
StreamNotFound when not connecting to a FMS means that you either have the path wrong or its not seeing it, due to a security issue.
var xml:XML = <myXml>
<item prop="1" />
<item prop="2" />
</myXml>;
I need to save as xml file in local harddisk(project directory).
Is it possible to save in as3 itself?
I threw this together, and sure enough you can save to .XML using the following as a minimalist example.
package com.hodgedev.xmlcreator
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.utils.ByteArray;
import flash.net.FileReference;
/**
* ...
* #author Brian Hodge (brian#hodgedev.com)
*/
public class Main extends Sprite
{
private var _xml:XML;
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);
//Calling the save method requires user interaction and Flash Player 10
stage.addEventListener(MouseEvent.MOUSE_DOWN, _onMouseDown);
_xml= <xml>
<test>data</test>
</xml>;
}
private function _onMouseDown(e:MouseEvent):void
{
var ba:ByteArray = new ByteArray();
ba.writeUTFBytes(_xml);
//ba.
var fr:FileReference = new FileReference();
fr.addEventListener(Event.SELECT, _onRefSelect);
fr.addEventListener(Event.CANCEL, _onRefCancel);
fr.save(ba, "filename.xml");
}
private function _onRefSelect(e:Event):void
{
trace('select');
}
private function _onRefCancel(e:Event):void
{
trace('cancel');
}
}
}
There are some things to note.
You require Flash Player 10 to use the save method of the FileReference class.
In order to do anything that INVOKES a prompt, Flash requires user interaction like keyboard or mouse input.
In the above I listen for MouseEvent.MOUSE_DOWN on the stage to serve as the USER INTERACTION which is required to invoke the save prompt.
I setup a basic XML structure within the code (this will typically come from and external source and will work fine both ways.
A ByteArray is created and the XML is written to the ByteArray.
The save method of the FileReference class requires a ByteArray and default save name be passed as the two parameters.
I hope this helps.
if you want to store it locally (on the client PC) , you can use a local shared object. Refer to this tutorial
I'm sorry, your question isn't very clear.
Are you asking if you can save a file to the hard drive from within a compile SWF written in AS3?
Or are you asking if you can include a raw XML file in your AS3 project without needing to write it out as a variable?
If you meant the former, no -- not without Adobe AIR. You can save data locally as a SharedObject, but not as an arbitrary file in the file system.
If the latter, then yes -- you must embed the file just as you would embed another resource (such as an image or a sound). However, it looks like there might be a bug in Flash that makes this non-trivial to figure out how to do.
This link might be of help to you.
[Embed(source='../../../../assets/levels/test.xml', mimeType="application/octet-stream")]
public static const Level_Test:Class;
And then to parse the XML:
var ba:ByteArray = (new Levels.Level_Test()) as ByteArray;
var s:String = ba.readUTFBytes( ba.length );
xml = new XML( s );
Apologies if neither of those questions are what you were actually asking.
Cheers!