Share Classes between Parent and Child SWF
So i have a situation where i want to pass a object of a class say 'MyBigAwesomeClass' from a c开发者_如何转开发hild to a parent. I import the class definition into both the parent and child.
Now, if i load the child swf from a location that is relative to the location of the parent , all is fine, however the moment i load it using a full absolute path, it treats the definitions for 'BigAwesomeClass' in parent and in child as different and does not allow an object of the type 'BigAwesomeClass' to be assigned to an object of the same in the parent class.
I am totally stumped, and have banged my head over ApplicationDomains, including using this code
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,swfLoaded);
var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
loader.load(new URLRequest(_file.url),context);
To absolutely no avail. Any ideas as to what can i do it fix this ?
Thanks in advance
According to Adobe's documentation (Loader#securityDomain):
In order for import loading to succeed, the loaded SWF file's server must have a policy file trusting the domain of the loading SWF file.
The trick is telling Loader to check the crossdomain file when loading the swf, by passing true
as the first parameter when creating the LoaderContext
, eg:
var request:URLRequest = new URLRequest(_file.url);
var context:LoaderContext = new LoaderContext(true, null, SecurityDomain.currentDomain);
var loader:Loader = new Loader();
loader.load(request, context);
The accompanying cross-domain.xml should be located in the same location as the child SWF, or in one of its parent folders. Here's a non-restrictive cross-domain file according to documentation from Adobe:
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<site-control permitted-cross-domain-policies="all"/>
<allow-access-from domain="*" secure="false"/>
<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
</cross-domain-policy>
One other thing that might make this easier for you, is to pass the interface instead of the class, which would effectively bypass conflicting code. This will work because the child inherits the interface from the parent class by default at runtime (see Loader#applicationDomain point #1). The child class can then safely instance it's own version of each object as long as that object adheres to the interface. For example:
var applicationDomain:ApplicationDomain = loader.contextLoaderInfo.applicationDomain;
var classDefinition:Class = applicationDomain.getDefinition("MyBigAwesomeClass") as class;
var instance:IMyBigAwesomeInterface = new classDefinition() as IMyByAwesomeInterface;
The definition for MyBigAwesomeClass would then look something like this:
public class MyBigAwesomeClass implements IMyBigAwesomeInterface
{
...
}
Well it turns out its a Sandbox Issue. Files that are not part of the installer are placed in a different Security Sandbox, and since they reside in different sandboxes, the child when imported into the parent does not inherit the definitions of its Parent in the ApplicationDomain
and two separate definitions exist which are incompatible. Sadly, there seems to be no direct way of resolving this. Adobe does allow communication between sandboxes via the SandBoxBridge, but that forces you to use Object type, which kind of defeats the purpose of the whole thing. As far as i can tell there is no way for classes in two different sandboxes to be compatible even though they are exactly the same. I guess its back the painfull world of no strict typing with Objects.
I would agree with you that the problem probably has to do with the parent & child's Application Domain, but in order to answer more accurately , it 'd be good to have some example use of the class you would like to share between the parent and the child.
In theory it seems the problem could be avoided if a class was defined for the child as well... Here's a very basic example that in my opinion should work wherever you load the child from.
package com.example.test { public class Parent extends Sprite { private var child:Child; private var shared:SharedClass = new SharedClass(); public function Parent() { loadChild(); } private function loadChild():void { // load process } private function loadComplete(event:Event):void { child = event.currentTarget.content as Child; if( child != null ) shared = child.shared; // remove event etc... } } } package com.example.test { public class Child extends Sprite { // I use a public var here , but you can use a getter... public var shared:SharedClass; public function Child() { shared = new SharedClass(); } } } package com.example.test { public class SharedClass { public function SharedClass() { trace('Hello from Shared Class'); } } }
One option is to use implement a method in the child class to return an instance of the class using it's own applicationDomain, eg:
public class Child extends Sprite implements IMyBigAwesomeClassLoader
{
public function getMyByigAwesomeClass():IMyBigAwesomeClass
{
var classDefinition:Class = applicationDomain.getDefinition("MyBigAwesomeClass");
var instance:IMyBigAwesomeClass = new classDefinition() as IMyBigAwesomeClass;
return instance;
}
}
The IMyBigAwesomeClassLoader
would look like this:
public interface IMyBigAwesomeClass
{
function getMyBigAwesomeClass():IMyBigAwesomeClass;
}
The parent clip would then use this to get the instance from the child when it's loaded:
public function loadCompleteHandler(event:Event):void
{
var myBigAwesomeClassLoader:IMyBigAwesomeClassLoader = (event.target as Loader).content as IMyBigAwesomeClass;
myBigAwesomeClass = myBigAwesomeClassLoader.getMyBigAwesomeClass();
}
The reason to use interfaces here is to decouple the class definition from its implementation. Even though the class in the parent and child SWFs have the same name, Flash treats them as different classes. The interface tells Flash that they can be used in the same way even though they are different.
Flash uses static typing, which means that once a class is defined it will never change, which means it will never over-write one class definition with another. So if there are two classes with the same name, it is necessary to use getDefinition
to resolve the conflicting names. If you want to avoid this added complexity, you can use different names or name-spaces for the class in the parent and child SWFs.
精彩评论