Совместное использование классов между родителями и детьми SWF - PullRequest
2 голосов
/ 13 августа 2011

Итак, у меня есть ситуация, когда я хочу передать объект класса, скажем, «MyBigAwesomeClass», от дочернего элемента к родительскому. Я импортирую определение класса и в родительский и в дочерний.

Теперь, если я загружаю дочерний SWF из местоположения, относящегося к местоположению родителя, все в порядке, однако в тот момент, когда я загружаю его, используя полный абсолютный путь, он обрабатывает определения для BigAwesomeClass в родительском. и у потомка как отличающийся и не позволяет объекту типа 'BigAwesomeClass' быть назначенным объекту того же самого в родительском классе.

Я полностью озадачен и ударил себя по доменам приложений, включая использование этого кода

loader.contentLoaderInfo.addEventListener(Event.COMPLETE,swfLoaded);
var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain); 
loader.load(new URLRequest(_file.url),context);

Безрезультатно. Любые идеи относительно того, что я могу сделать, это исправить?

Заранее спасибо

Ответы [ 4 ]

1 голос
/ 14 августа 2011

Ну, оказывается, проблема с песочницей. Файлы, которые не являются частью установщика, помещаются в другую изолированную программную среду безопасности, и, поскольку они находятся в разных изолированных программных средах, дочерний объект при импорте в родительский объект не наследует определения своего родительского элемента в ApplicationDomain, и существуют два отдельных определения, которые несовместимы К сожалению, кажется, нет прямого способа решить эту проблему. Adobe разрешает связь между песочницами через SandBoxBridge , но это вынуждает вас использовать тип объекта, что противоречит цели всего этого. Насколько я могу судить, классы в двух разных песочницах не могут быть совместимы, даже если они абсолютно одинаковы. Я полагаю, он вернулся в мучительный мир отсутствия строгой печати с помощью объектов.

1 голос
/ 13 августа 2011

Согласно документации Adobe ( Loader # securityDomain ):

Чтобы загрузка импорта прошла успешно, сервер загруженного SWF-файла должен иметь файл политики, доверяющий домену загружаемого SWF-файла.

Хитрость заключается в том, чтобы Loader проверял файл междомена при загрузке SWF, передавая true в качестве первого параметра при создании LoaderContext, например:

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);

Прилагаемый файл cross-domain.xml должен находиться в том же месте, что и дочерний SWF-файл, или в одной из его родительских папок. Вот неограничивающий междоменный файл в соответствии с документацией 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>

Еще одна вещь, которая может упростить это для вас, - передать интерфейс вместо класса, что эффективно обойдёт конфликтующий код. Это будет работать, потому что дочерний объект наследует интерфейс от родительского класса по умолчанию во время выполнения (см. Loader # applicationDomain point # 1). Затем дочерний класс может безопасно создавать свою собственную версию каждого объекта, если этот объект придерживается интерфейса. Например:

var applicationDomain:ApplicationDomain = loader.contextLoaderInfo.applicationDomain;
var classDefinition:Class = applicationDomain.getDefinition("MyBigAwesomeClass") as class;
var instance:IMyBigAwesomeInterface = new classDefinition() as IMyByAwesomeInterface;

Определение для MyBigAwesomeClass будет выглядеть примерно так:

public class MyBigAwesomeClass implements IMyBigAwesomeInterface 
{
    ...
}
0 голосов
/ 14 августа 2011

Одним из вариантов является использование реализации метода в дочернем классе для возврата экземпляра класса с использованием его собственного applicationDomain, например:

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;
   }
}

IMyBigAwesomeClassLoader будет выглядеть так:

public interface IMyBigAwesomeClass 
{
  function getMyBigAwesomeClass():IMyBigAwesomeClass;
}

Затем родительский клип будет использовать его для получения экземпляра от дочернего элемента при загрузке:

public function loadCompleteHandler(event:Event):void
{
  var myBigAwesomeClassLoader:IMyBigAwesomeClassLoader = (event.target as Loader).content as IMyBigAwesomeClass;
  myBigAwesomeClass = myBigAwesomeClassLoader.getMyBigAwesomeClass();
}

Причина использования интерфейсов здесь состоит в том, чтобы отделить определение класса от его реализации. Хотя класс в родительских и дочерних SWF-файлах имеет одинаковые имена, Flash рассматривает их как разные классы. Интерфейс сообщает Flash, что их можно использовать одинаково, даже если они разные.

Flash использует статическую типизацию, что означает, что после определения класса он никогда не изменится, что означает, что он никогда не перезапишет одно определение класса другим. Поэтому, если есть два класса с одинаковыми именами, необходимо использовать getDefinition для разрешения конфликтующих имен. Если вы хотите избежать этой дополнительной сложности, вы можете использовать разные имена или пространства имен для класса в родительских и дочерних SWF-файлах.

0 голосов
/ 13 августа 2011

Я бы согласился с вами, что проблема, вероятно, связана с доменом приложения родителя и ребенка, но для более точного ответа было бы неплохо привести пример использования класса, которым вы хотели бы поделитьсяродитель и ребенок.

Теоретически кажется, что проблемы можно избежать, если бы класс был определен и для ребенка ... Вот очень простой пример, который, по моему мнению, должен работать везде, где вы загружаете ребенка.

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');
      }
   }
}
...