It's possible to write a sharedobject when allowscriptaccess is = "never"? - actionscript-3

I will try to write a sharedObject item using my swf embeded into an html page.
"allowscriptaccess" is setted to "never". I can't write sharedObject!
However if I set allowscriptaccess to "always", write action work well...
If I can't use sharedObject with allowscriptaccess setted to never, exist alternative for saving data?
I write a little and stupid example:
public class Main extends Sprite {
private var SHARED_NAME:String = "__SO__";
private var so:SharedObject;
Security.allowDomain("*");
Security.allowInsecureDomain("*");
public function Main() {
this.so = SharedObject.getLocal(this.SHARED_NAME, "/");
this.setSharedObj("YEAHHHHHHHH");
this.getSharedObj();
}
public function getSharedObj(clientId:String = null):Object {
var url:String = "http://localhost:8080?so=" + this.so.data.test;
var request:URLRequest = new URLRequest(url);
var loader:URLLoader = new URLLoader();
loader.load(request);
return this.so.data;
}
public function setSharedObj(setValue:String):void {
this.so.data.test = setValue;
this.so.flush();
}
}
When embed the compiled swf using AllowScriptAccess: "never", get Request never have setted the queryparam so.
If set AllowScriptAccess to "always" queryparam will be correctly setted

#akmozo is right, the problem was not related by AllowScriptAccess, but from my way of testing.
The problem is:
Using firefox in anonymous mode, every time you reload the page, shared object are deleted.
I thought for anonymous session are saved, it is not so!

Related

AS3: Reusing URLLoader, URLRequest, and URLVariables instances

My Flash project uses URLLoader.load a lot to load content from a web server and post to a php page. Should I reuse my URLLoader, URLRequest, and URLVariables instances, or should I create new ones each time? If I should create new ones each time, do the old ones need to be disposed of somehow?
You should most certainly never ever ever reuse any instances related to external operations and you should thoroughly dispose of them the very moment you don't need them. The overhead of Garbage Collector (GC) working on these objects is literally nothing next to the nightmare mess you might get into once your external operations collide via sharing the same operational instances.
URLVariables and URLRequest do not need any special treatment, just set null to any variables referencing them and ensure that method, where they were assigned to local variables, do not produce any function closures. Well, set URLRequest.data to null to break this reference.
URLLoader, on the other hand, needs to be pushed around a bit:
If URLLoader.data is a ByteArray, then you should ByteArray.clear() it (unless you need it).
Set the URLLoader.data to null.
Initially subscribe all error handlers with weak references (fifth argument of addEventListener set to true) and don't unsubscribe them. Weak keys won't affect the GCs judgement while keeping the subscriptions might save you from occasional Unhandled Error Event case.
Certainly do unsubscribe all non-error handlers.
In all the handlers, first check if Event.target is a valid URLLoader instance to avoid handling an event from a dead/disposed URLLoader.
Call URLLoader.close() just in case. Yes, after all of above is done.
Below is the class I use to load things in a simple way. It is built on the same principles I listed above. It allows loading text/binary data and also provides some proof against unstable network: you can set the repeatCount argument to higher values to provide fail-safe loading if you know that requests tend to fail sometimes.
Usage:
// Load binary data over unstable network.
DataFiles.load("data.dat", onData, true, 10);
// Load XML file as text over a stable network or from the local storage.
DataFiles.load("setup.xml", onSetup);
function onData(source:ByteArray):void
{
if (!source)
{
// Loading failed. Error case.
}
else
{
// File is loaded normally.
}
}
function onSetup(source:String):void
{
try
{
var aSetup:XML = new XML(source);
// Process loaded XML normally.
}
catch (fail:Error)
{
// The source is either null or an invalid XML string.
// Loading is failed, basically. Error case.
}
}
Implementation:
package simplify
{
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLLoaderDataFormat;
public class DataFiles
{
static private var list:Vector.<DataFiles> = new Vector.<DataFiles>;
static public function load(url:String, handler:Function, binary:Boolean = false, repeatCount:int = 1):void
{
var aLoader:DataFiles = new DataFiles;
aLoader.url = url;
aLoader.binary = binary;
aLoader.handler = handler;
aLoader.repeatCount = repeatCount;
list.push(aLoader);
aLoader.start();
}
private var url:String;
private var binary:Boolean;
private var handler:Function;
private var loader:URLLoader;
private var repeatCount:int;
private function start():void
{
loader = new URLLoader;
if (binary) loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.COMPLETE, onComplete);
loader.addEventListener(IOErrorEvent.IO_ERROR, onError, false, 0, true);
loader.load(new URLRequest(url));
}
private function destroyLoader():void
{
if (!loader) return;
loader.removeEventListener(Event.COMPLETE, onComplete);
var aDead:Loader = loader;
loader = null;
aDead.data = null;
aDead.close();
}
private function onComplete(e:Event):void
{
if (e.target != loader) return;
var aResult:* = loader.data;
var aHandler:Function = handler;
destroy();
destroyLoader();
aHandler(aResult);
}
private function onError(e:IOErrorEvent):void
{
if (e.target != loader) return;
destroyLoader();
repeatCount--;
if (repeatCount >= 0)
{
start();
}
else
{
var aHandler:Function = handler;
destroy();
aHandler(null);
}
}
private function destroy():void
{
var anIndex:int = list.indexOf(this);
if (anIndex > -1) list.splice(anIndex, 1);
handler = null;
url = null;
}
}
}

as3 loaded swf accessing variables

I have some questions with sharing/using/accessing variables/functions between loaded swf files.
my prj consists of main.swf file and 2 swf's which I load on first init of the main.swf.
my questions are:
1.how can I use variables from 1.swf in 2.swf (function is running in 2.swf)
2.how can I call a function from 2.swf in 1.swf
here is the code I'm using to load the swf's:
var playerMc:MovieClip = new MovieClip();
var dbMc:MovieClip = new MovieClip();
var m2Loader:Loader = new Loader();
var mLoader:Loader = new Loader();
startLoad();
function startLoad()
{
//var mLoader:Loader = new Loader();
var mRequest:URLRequest = new URLRequest("./_player/player.swf");
mLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadMc);
mLoader.load(mRequest);
addChild(mLoader);
//var m2Loader:Loader = new Loader();
var m2Request = new URLRequest("./_db/db.swf");
m2Loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadMc2);
m2Loader.load(m2Request);
addChild(m2Loader);
}
function loadMc(event:Event):void
{
if (! event.target)
{
return;
}
playerMc = event.target.content as MovieClip;
mLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadMc);
}
function loadMc2(event:Event):void
{
if (! event.target)
{
return;
}
dbMc = event.target.content as MovieClip;
dbMc.x = -400;
m2Loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadMc2);
}
You have to stick with application domain.
In most cases you should load another swf in another application domain, but it's not really related to your question.
From loader, you must access to applicationDomain and then getDefinition. From there, you can get classes and use them in your main swf. Yes, you can read static properties.
If you need instances you should access loader#content. It is pointing to a root of loaded SWF. Root of loaded is SWF – is the instance of main class of the loaded swf.
Create a variable with no definition such as
public var MyClass;
as you can see i didnt add
public var MyClass:Class;
then in another function write
this.MyClass = this.mLoader.contentLoaderInfo.applicationDomain.getDefinition("NameOfClass") as Class;
i dont know much about this myself.. im having problems figuring out if you can only access Public static variables or if its possible to access normal public variables and possibly private variables because it is creating a new instance of the same class or however you want to word it..?
also after your write the above code .. when you want to change a varaibles this usually works for me
this.MyClass.RandomVariableName = this.MyClass.RandomVariableName + 1;
something like that..

AS3 Serialization

What I'm trying to do:
-Have objects in a toolbar, drag and dropable onto a movieclip (they then become a child of the movieclip). Once this is done, I want to be able serialize this object, so I can save it to a file. Then, I can reload this file, and continue draging/dropping things onto/off of this movieclip.
How I'm doing it:
public class Serialization {
public static function serializeToString(value:Object):String{
if(value==null){
trace("null isn't a legal serialization candidate");
}
var bytes:ByteArray = new ByteArray();
bytes.writeObject(value);
bytes.position = 0;
var be:Base64Encoder = new Base64Encoder();
be.encode(bytes.readUTFBytes(bytes.length));
return be.drain();
}
public static function readObjectFromStringBytes(value:String):Object{
var dec:Base64Decoder=new Base64Decoder();
dec.decode(value);
var result:ByteArray=dec.drain();
result.position=0;
return result.readObject();
}
}
This is where call the function/write it to the file:
var fr:FileReference = new FileReference;
fr.addEventListener(Event.COMPLETE, success);
var txtString:String = new String();
txtString = save.Serialization.serializeToString(pagePic);
trace(txtString);
fr.save(txtString, "test.txt");
Unfortunately, txtString appears to be blank. Am I approaching this wrong?
Side notes:
This is being developed for a mobile platform.
Unfortunately MovieClips, Sounds, and other resources cannot be serialized. My solution is to create a custom class that will store all my properties and reassign them upon loading, or just write to/parse a text file when saving/loading.

Cross domain problems in Flash

I have two swf files hosted on different domains aaa.com/a.swf and bbb.com/b.swf. a.swf is loading b.swf and trying to cast it to some interface. When both of these swf files are under the same domain everything works fine. But when they are under different domains I'm getting null after casting b.swf to the implemented interface IComponent. Both of these swfs are compiled with use-network=true and with the same IComponent.as.
public class Wrapper extends Sprite
{
public function Wrapper()
{
super();
var request:URLRequest = new URLRequest("http://aaa.com/Component.swf");
var loaderContext:LoaderContext = new LoaderContext();
loaderContext.applicationDomain = ApplicationDomain.currentDomain;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoadingComplete);
loader.load(request,loaderContext);
addChild(loader);
}
private function onLoadingComplete(event:Event):void
{
var target:LoaderInfo = event.target as LoaderInfo;
var component:IComponent = target.content as IComponent;
component.init({"s":1});
component.run();
}
}
public class Component extends Sprite implements IComponent
{
public function Component()
{
super();
Security.allowInsecureDomain("*");
}
public function init(params:Object):void
{
//some actions
}
public function run():void
{
//some actions
}
}
Try this:
//Assuming you've set a crossdomain policy file
var loaderContext:LoaderContext =
new LoaderContext( true , ApplicationDomain.currentDomain )
It seems that the reason why it's not working has to do with the fact that either IComponent is not recognized or that there's a definition conflict. I would have thought that with ApplicationDomain set to currentDomain, a definition conflict should have been avoided... but it may be worth trying to leave each SWF within their own domain.
//Assuming you've set a crossdomain policy file
var loaderContext:LoaderContext =
new LoaderContext( true );
You could also check if IComponent "exists" before loading the other SWF. This could help in diagnosing what's going on...
var ClassName:Object = getDefinitionByName('IComponent');
trace( ClassName );
Maybe you have to set cross-domain security policy by crossdomain.xml file
http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security.html
For example:
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy
SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*.example.com" />
</cross-domain-policy>
Thanks all for answers, I've found a working solution today.
Instead of casting loaded content to IComponent I'm casting it to object
var component:Object = (event.target as LoaderInfo).content as Object;
component["init"](null);
component["run"]();
I's confimed from testing that even when we are using shared class with static fields and methods it doesn't work. Both of wrapper and component are instantiating their own instances of shared class. It's really strange.
If you have the same problems please ensure that your wrapper/component classes have Security.allowDomain calls
This is a bug in the player:
http://bugs.adobe.com/jira/browse/ASC-3529
It happens when you try to "share" an interface between swfs that were loaded from different domains. This should work provided that you put both swfs under the same app domain (as you have).
Using an Object works, but kind of defeats the purpose of using an interface in the first place.
Here's a workaround that basically loads the swf as a binary and then uses Loader::loadBytes to actually load the swf into memory:
http://blog.aleksandarandreev.com/?p=42
my idea about syntax errors was pointless, here's an edit:
this code:
private function ololo():void{
var request:URLRequest = new URLRequest("http://domain/file.swf");
var loaderContext:LoaderContext = new LoaderContext();
loaderContext.applicationDomain = ApplicationDomain.currentDomain;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoadingComplete);
loader.load(request,loaderContext);
}
private function onLoadingComplete(e:Event):void {
var target:LoaderInfo = e.target as LoaderInfo;
addChild(target.content as Sprite);
}
works well even if files are on completely different domains.
does it work if you treat your IComponent as Sprite?

Loaded swf does not display

I am trying to use the Loader class to load an swf animation. If I do addChild(ldr); the animation is displayed and perma-looped, but if I try it as below, the animation doesn't display.
public var ldr:Loader;
public var explosion:MovieClip;
public var req:URLRequest;
ldr = new Loader();
req = new URLRequest("../graphics/explosion1.swf");
ldr.load(req);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);
and
public function onCompleteHandler(loadEvent:Event):void {
explosion = ldr.content as MovieClip;
addChild(explosion);
}
Any ideas? Thanks!
not sure, but it may be a simple security problem : loaderInfo.content is subject to security restrictions : http://help.adobe.com/fr_FR/AS3LCR/Flash_10.0/flash/display/LoaderInfo.html#content
so then your ldr.content as MovieClip fails silently, and explosion is null :)
addChild(ldr) should be just fine for what you're doing, but if you really need access to contentLoaderInfo.content, you should either use Security.allowDomain(domain of your main app) in your explosion1.swf or set a crossdomain policy in the repertory.
hope this helps.