使用类级嵌入访问MainTimeline符号

时间:2012-01-18 19:14:10

标签: flash actionscript-3 air

以下是该方案:

我们拥有一个在Flash CS5.5中运行的创意团队,并生成包含图形元素和动作脚本代码的SWF资产,以及一个创建.as文件并构建“代码SWF”的工程团队。代码SWF文件必须加载或嵌入广告素材资源,并与其中的代码进行交互,以使我们的应用能够正常运行。

对于iOS移动开发,还有另一个考虑因素 - 由于Apple TOS,无法在iOS的AIR应用程序包中加载运行时代码(请参阅related question)。因此,无法使用Loader在iOS环境中加载SWF并保留其代码。

将SWF嵌入到ActionScript文件中的标准方法会导致Loader直接将嵌入的SWF作为字节加载。这导致访问顶级主时间轴,如下所示:

[Embed(source="embed_test.swf")]
  private var no_aot_support:Class;

public function main():void
{
  var no_ios:* = new no_aot_support();
  addChild(no_ios);
  no_ios.addEventListener(Event.COMPLETE, function():void {
    var timeline:MovieClip = no_ios.getChildAt(0).getChildAt(0);
    trace(timeline.foo); // foo variable exists, output is 'blah'
  });
}

但是,这种嵌入机制在iOS设备上不起作用,因为每个Apple的TOS都不允许运行时代码 - 所有代码必须在编译时通过提前编译器(AOTCompiler)和SWF传递以这种方式嵌入不符合此标准。

询问周围,我found可以使用类级嵌入来解决这个问题,因为类级嵌入确实会通过编译器并导致在iOS下运行代码:

package
{
  import flash.display.MovieClip;

  [Embed(source="embed_test.swf", symbol="Symbol1")]
   public final dynamic class anim extends MovieClip { };
}

这很好用,但是我不想在SWF中引用一个符号,我想要整个swf(也就是引用主时间轴),但是下面会导致编译错误:

package
{
  import flash.display.MovieClip;

  [Embed(source="embed_test.swf")]
   public final dynamic class anim extends MovieClip { };
}

我还反编译了SWF,找到了主时间轴符号,并尝试了这个:

package
{
  import flash.display.MovieClip;

  [Embed(source="embed_test.swf", symbol="embed_test_fla.MainTimeline")]
   public final dynamic class anim extends MovieClip { };
}

但是编译器坚持认为这个符号不存在。

由于我有很多很多SWF资产,我需要一个不涉及改变整个工作流程的解决方案(即进入每个FLA并进行更改)。这应该是可能的,如果没有,这是Adobe应该解决的工作流问题。

所以在这里我被困 - 常规嵌入获得MainTimeline但在iOS中不起作用,类级嵌入在iOS中工作并且无法访问MainTimeline。

随意download my expample project并玩这个。

2 个答案:

答案 0 :(得分:5)

在主时间轴上放置对象始终会在SWF文件中生成生成的代码:Flash IDE会为应用程序生成所有必需的代码,也就是说,它会创建文档类的实例在运行时放在舞台上。但是,这是无法访问的代码,除非通过加载器对象加载SWF - 既不使用[嵌入],也不生成SWC将允许它。

我已尝试导出SWC,因为像@ 32bitkid我认为这是一种绕过限制的方法。事实证明,你可以实例化文档类,即使你没有显式声明它并让IDE自动生成它。但是,所有舞台实例都消失了。 :(你也可以声明一个自定义文档类,并使用addChild()将你的库对象放在舞台上 - 然后一切正常。但是你在IDE的主时间轴上做的任何事情,你都无法访问永远。

这也是有道理的:对象实际上是放置在主时间轴实例上的阶段实例。但是一旦你打电话给new MyDocumentClass(),你就会创建一个新实例 - 它还没有任何成员。

奇怪的是,所有这些对于任何库对象都应该是正确的 - 将对象实例放置在库对象时间线中也应该需要代码生成,不应该吗? - 但它实际上并不完全相同:当您调用new MyLibraryObject();时,您在库对象中放置在舞台上的任何内容仍然存在并且可以访问。

因此。我看到你的项目工作的唯一方法是让你的设计师在每个FLA的库中创建一个唯一命名的“时间轴”MovieClip(或Sprite),并导出为ActionScript。 (您不能总是使用“时间轴”,因为在使用多个SWC时会出现命名冲突)然后使用此“时间轴”将任何必要的对象直接放在舞台上,添加帧代码等。在其中,设计人员可以完全按照他们习惯的方式工作,除了设备硬件和可用的API之外没有任何限制。唯一真正的区别是FLA本身的主时间轴上根本不存在任何东西。

然后,您可以使用SWC方法(这比手动生成[嵌入]代码要简单得多)并在主应用程序中实例化“时间轴”符号 - 一切都应该在您需要的地方。

答案 1 :(得分:0)

我正在发布我自己的解决方案来解决这个问题,以防这个问题发生:

此处有更详细的回复:Is it possible to embed or load SWFs when making iphone apps (Is it allowed by Apple)

我已经创建了一个工具来解决此问题,方法是将嵌入式SWF合并到主SWF中。通过这种方式,嵌入是AOT编译并转换为objective-c代码,因此我获得了我的资产实例(主时间轴),并且资产的代码被正确交叉编译以在iOS设备上工作。

它使用这样的嵌入工作:

[Embed(source="GameLevel.swf")]
  private var GameLevel:Class;

public function main():void
{
  var my_level:* = new GameLevel();
  addChild(my_level);
}

在这种情况下,如果gameLevel.swf中包含代码,它通常在iOS中不起作用,因为新的gameLevel()会创建一个Loader并解释SWF字节码。但是,如果您首先通过我的名为SWFMerge的工具运行上述SWF,它将采用您的嵌入式SWF并将其合并到您的根SWF中。然后ADT会将你的主swf(包括嵌入代码)编译成objective-C,它将在iOS上工作,并注意:new gameLevel()现在直接在你的资产实例中产生 - 而不是一个Loader。

SWFMerge工具在此处:

http://www.onetacoshort.com/temp/SWFMerge_alpha.swf

如果此解决方法适合您或您遇到问题,请在评论中告诉我。

我将补充一点,使用SWC工作流程更好并得到官方支持,但是如果您没有原始FLA源文件,或者只是想快速使用包含代码的现有资产,这种解决方法很有用它们。