I have a .swf file that uses the following code:
private function onClick(e:MouseEvent):void {
var popUpClass:Class = getDefinitionByName(e.currentTarget.popUp) as Class;
popUpContent = new popUpClass();
}
However when I load that swf into another "container" swf I am getting a Reference Error #1065. I have been reading several posts on stack overflow (for example, this one and this one) but I am still confused as to what to do.
For example, do I change the code in my "loaded swf" to reference it's own application domain (not the domain of the container swf?) and if so, how do I do this exactly?
OR do I load the swf file and assign it it's own application domain in the code of the container? (not the code for the loaded swf?)
Also, my "e.currentTarget.popUp" just has a short name "PopUpWhateverName" should I be giving it a full package name like "com.MyLoadedSwf.Assets.PopUpWhateverName"?
Yes , full package name : getDefinitionByName("com.MyLoadedSwf.Assets.PopUpWhateverName")
but You can also try :
var popUpClass:Class = e.currentTarget.popUp.constructor;
popUpContent = new popUpClass();
Related
I need to read a part of two files, and once both parts of both files are loaded to trigger a function that does some work.
What is the best way to approach this problem.
I am currently triggering the second file load once the first is loaded, however it seems poor coding style, I think this because my OO code starts looking procedural.
EDIT: So its an Air based app so using filestream.
In the end I found I actually needed to read each file in a different way. Because I need the same part of both files, and I dont know the file size, I need to read one file first and once I have fileStream.bytesAvailable and position, I can then look for the same data from the second file. I found I must handle files smaller than my read size and the end of files beyond multiples of my read size.
You don't specified what file and from where you wont to load the file but you can actually load multiples files in parallel.
If you want to read only part of file from local machine you can use AIR's FileStream class - very easy and you don't have to load whole few hundreds MB file:
import flash.filesystem.*;
var file:File = File.documentsDirectory;
file = file.resolvePath("Apollo Test/test.txt");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
var str:String = fileStream.readMultiByte(file.size, File.systemCharset);
trace(str);
fileStream.close();
Another option is to use URLStream and listen for ProgressEvent.PROGRESSevents to read data of partially loaded file.
You may also want to see NetStream class which is used to stream video.
there is many options, using File, FileStream is only available on air applications.
The File class extends the FileReference class. The FileReference
class, which is available in Flash® Player as well as Adobe® AIR®,
represents a pointer to a file, but the File class adds properties and
methods that are not exposed in Flash Player (in a SWF running in a
browser), due to security considerations.
as noted above, if you are creating a non-AIR application, FileReference should be used instead of FileStream and File classes, as you dont tagged AIR in your question.
FileReference does not provide any open("path") to you (due to security considerations), but a browse method will be available and ask's your client's for selecting a file. here is an example, which also explain how to trigger a function when opening is done:
var filereference:FileReference = new FileReference();
filereference.addEventListener(Event.SELECT, onFileSelected);
var text_files:FileFilter = new FileFilter("Text Files","*.txt; *.html;*.htm;*.php");
var all_files:FileFilter = new FileFilter("All Files (*.*)","*.*");
filereference.browse([text_files, all_files]);
// triggered when a file is selected by user
function onFileSelected(e:Event):void {
filereference.removeEventListener(Event.SELECT, onFileSelected);
filereference.addEventListener(Event.COMPLETE, onFileLoaded);
filereference.load();
}
// triggered when file loading is complete
function onFileSelected(e:Event):void {
var data:ByteArray = fileReference["data"];
filereference.removeEventListener(Event.COMPLETE, onFileSelected);
}
two more events to be listened for suddenly error's occurred and displaying a progress bar for loading progress (its sync):
IOErrorEvent.IO_ERROR and ProgressEvent.PROGRESS
How can I patch actionscript without constantly rebuilding sfw?
There is a fairly large actionscript project that I need to modify and resulting swf is used on a live site. The problem I have is that I need to make quick small updates to the swf and it's not acceptable to update the swf on live site ten time a day (I don't control that part, I need to ask another person to put the result on live site).
What options do I have to workaround that issue? I'm a complete noob when it comes to actionscript and all flash related stuff and I'm not even sure what is possible and what isn't. I'm thinking about the following approaches, which ones are possible/acceptable?
Imagine that live site is on www.livesite.com/game.html and this page loads www.livesite.com/flashgame.swf. In that flashgame.swf among many others there is a class com/livesite/Magic.as that gets instantiated and instance of that class has a member variable xxx123 of class com/livesite/MagicWork.as. I only need to modify this MagicWork class. Now, I simply modify it, build and ask to put updated flashgame.swf live. So, I want to avoid that manual step.
All my ideas can be split in two basic approaches: 1) keep flashgame.swf totally unmodified and then load flashgame.mod.swf that contains alternative implementation of that MagicWork class, then using javascript access internals of instance of that Magic class and update its xxx123 member to be an instance of MagicWork class from flashgame.mode.swf. I'd need to modify game.html to load my javascript so that my js file would load flashgame.mod.swf and patch code inside flashgame.swf. By patching I mean javascript-style overwriting of Magic.xxx123 to a new value. flashgame.mode.swf would ideally reside on my own host that I control. Is that kind of stuff possible, if not what's not possible?
2) I could make one-time change in flashgame.swf so that it would effectively load itself my own code at runtime and patch it's xxx123 member. Is that possible?
I had already written a note about loading runtime shared libraries previously. I'll put the most essential parts of the process here, and add a link to the full article at the end.
You need to tag your main application entry point in the following manner.
[Frame(factoryClass="Preloader")]
public class Main extends Sprite
{
}
Then create a class called Preloader.
public class Preloader
{
public function Preloader()
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.loader_completeHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, this.loader_ioErrorHandler);
var request:URLRequest = new URLRequest("math.swf");
var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
loader.load(request, context);
}
private function loader_completeHandler(event:Event):void
{
var mainClass:Class = getDefinitionByName("Main") as Class;
var mainInstance:Main = new mainClass();
this.addChild(mainInstance);
}
}
The full implementation of the Main class is like this.
[Frame(factoryClass="Preloader")]
public function Main()
{
var integer:IntegerArithmetic = new IntegerArithmetic(); // Type declared in math.swf
var operand1:int = 10;
var operand2:int = 10;
var result:int = integer.add(operand1, operand2);
}
Deploying Runtime Shared Libraries
The confusing bit about using a runtime shared library is realizing that the SWF has to be extracted from the SWC at the time of deploying the application. This was not immediately obvious and I ended up spending days placing a compiled SWC file in various locations and wondering why the application was unable to load it at runtime. An obscure article on the Adobe website made explicit this particular step and set things straight.
The full article along with the same example is available at http://www.notadesigner.com/runtime-shared-libraries-with-plain-actionscript/.
I have three classes and a container .swf:
Game - this loads all assets and game mechanics.
Tile - Creates a square and loads image an image via flash Var.
TicTacToe.as - This creates a game instance and is linked via container.swf
In my Game class I have the following code which works fine when I save and compile, and is able to load my images when I update to my .asp page(I am getting the data from a db and passing to flash vars).
var gridUrl:String = "img/" + loaderInfo.parameters.theme + "grid.png";
var gridPos:XMLList = theXML.GRID;
gridLoader.load(new URLRequest(gridUrl));
grid = new MovieClip();
grid.addChild(gridLoader);
When I add this code to the Tile.as to load an image for the square I get a compiler error 1009: Cannot access a property or method of a null object reference. with an error on this line:
var tileBurl:String = "img/" + loaderInfo.parameters.theme + "square.jpg";
Its working in the Game.as class but this same line isn't in my Tile.as and I can't figure out why, even locally when it can't find the variables Game.as simply lists them as "undefined" where as in Tile.as it throws a fit at loaderInfo.parameters, and loaderInfo lists them as "null". Any Help would be appreciated thanks!
It looks that in the time of calling loaderInfo object, this is not yet prepared. Try to delay execution of the code for example by adding empty frame at the begining.
I have two SWFs, call them A and B. They will never be deployed to a website, and are being used for tools. B depends on A - some of the classes in B extend classes in A.
I am now creating a 3rd SWF, call it X. X is attempting to load A and B using a flash.display.Loader and flash.net.URLRequest. A and B paths are pushed into an array, and then called in a loadLibrary function like so:
public class LibraryLoader
{
private static const CLASS_NAME:String = "LibraryLoader";
private var _libraries:DisplayObjectContainer;
...
public function loadLibrary(callback:Function, libName:String):void
{
trace("loadLibrary('" + libName + "')");
var loader:Loader = new Loader();
loader.name = libName;
var listener:Function = function(e:Event):void
{
trace("finished loading '" + libName + "', event: " + e);
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, listener);
_libraries.addChild(loader);
callback();
}
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, listener);
loader.load(new URLRequest(libName));
}
Problem is, when I load B, it throws an error. Here's the output:
loadLibrary('C:\path\to\A.swf')
finished loading 'C:\path\to\A.swf', event: [Event type="complete" bubbles=false cancelable=false eventPhase=2]
loadLibrary('C:\path\to\B.swf')
[Fault] exception, information=VerifyError: Error #1014: Class a.class.in::A could not be found.
This class is inside A, and B depends on it.
I Googled around and found information about Security permissions and sandboxes - perhaps I need to set up some trust between these SWFs. That's fine, but I can't seem to figure out how to do it properly.
For one, I tried setting up a LoaderContext like so (when loading both SWFs):
var context:LoaderContext = new LoaderContext();
context.applicationDomain=ApplicationDomain.currentDomain;
loader.load(new URLRequest(libName), context);
No dice, there; same error. In addition, attempting to set context.securityDomain throws out:
[Fault] exception, information=SecurityError: Error #2142: Security sandbox violation: local SWF files cannot use the LoaderContext.securityDomain property. file:///C|/path/to/X.swf was attempting to load file:///C:/path/to/A.swf.
In case it makes a difference, A and B are being compiled using compc.exe from the Flex SDK (3.6). I generate both a SWF and a SWC for each - SWFs for runtime, and SWCs for compiling - using compc. Here is the command line for compc:
compc.exe -output C:\temp\dir -source-path -include-sources C:\path\to\A\source -directory=true -incremental=true -debug=true -use-network=false
compc.exe -output C:\path\to\A.swc -source-path -include-sources C:\path\to\A\source -incremental=true -debug=true -use-network=false
compc.exe -output C:\temp\dir -source-path -include-sources C:\path\to\B\source -directory=true -incremental=true -debug=true -external-library-path+=C:\path\to\A.swc -use-network=false
After the first and 3rd compilations, a "library.swf" file is dropped into the temporary directory listed. I take those SWFs out and rename them to A.swf and B.swf, dropping them where I want them.
My project for X is built in FlashDevelop 4.0.1 for Flash Player 10.1.
I know that a.class.in::A is included in SWF A. I am loading these SWFs in a Scaleform runtime with no issues, and am therefore convinced there is some kind of issue with how FlashPlayer is doing things.
How can I get B to see the classes inside A when I load A and B from X?
There are three comments:
You were right, when you specified the applicationDomain to ApplicationDomain.currentDomain; without this loader loads swf to separate child domains with common parent, so they don't see classes of each other.
With common application domain, classes from A must be accessible from B, so I see only one possibility for the error: A really hasn't class some.class.in.A. Try to check is this class is included to A (for example by Sothink SWF Decompiler) or simply check if this class is used explicitly in the code in A. if it isn't used it not be included, nut you can force to include this class by adding it in the code: simply add some.class.in.A some where in the A without new statement.
context.securityDomain is for other purposes, it is used only when swf files loaded by http, and don't applies locally.
This is my class in essence
import mx.controls.Image;
public class ImageFrameView extends Image
{
//Model. Contains x, y, z and z. Url for the png/jpg or swf-file
private var m_imageFrame:ImageFrame;
public function ImageFrameView(imageFrame:ImageFrame)
{
super();
m_imageFrame = imageFrame;
initFrameView();
}
private function initFrameView():void
{
maintainAspectRatio = false;
width = m_imageFrame.width;
height = m_imageFrame.height;
x = m_imageFrame.x;
y = m_imageFrame.y;
rotation = m_imageFrame.rotation;
source = m_imageFrame.url; //Url points to a handler on the same server which serves images and/or swf-files.
}
}
And it's used like this in a class SpreadView which extends UIComponent
var imageFrameView:ImageFrameView = new ImageFrameView(contentFrame as ImageFrame);
addChild(imageFrameView);
Png and Jpeg works fine. And swf-files which I export from Indesign CS4 or Indesign CS5 works fine aswell. But recently,older swf-files which have been exported using the same method and parameters (in Indesign CS4) and which used to work, have suddenly refused to load and I get the following error, when UpdateDisplayList is called for the ImageFrameView:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at com.adobe.indesign::IDSWFFile/readConfigurationData()
at com.adobe.indesign::IDSWFFile()
What happens is that the loaded swf-file throws an exception when it tries to read its own configuration.
All swf-files that I've created past and present still work. All swf-files that clients have created created past and present - doesn't work even tough they worked in the past. As far as I know the swf-files is created using the same method and parameters.
Can there be some sudden change in Adobe Flash that I'm not aware of? Me and my client is using Flash 10.1 or higher. Where does the error orgin from?
It seems like it is page transistions and/or page curl was the culprit. I don't know why but when I ticked off the options for page transistions the error vanished when the pdf is loaded. As such features is meaningless in my app I will make sure that such options is disallowed when the clients exports swf-files from indesign.