[转] 如何在 Flex Application 载入初期做事情

Ticore's Blog

如何在 Flex Application 载入初期做事情呢?
这裡指的不是 Application.preinitialize 事件
而是在 Application 尚未载入之前,SystemManager 初始化阶段
方法大致有三种:

1. 自行覆写 Preloader

Preloader 主要是负责表现 Application、RSL 下载进度
自然必须要在很早期开始运作而且能够存取到 stage
Preloader 原本定义就是作下载进度表现
拿它做其它事情似乎也不是很适合

How I (sort of) modified Flex's SystemManager.initialize() method

2. 使用 Mixin Class

Flex 提供了一个 Metadata Tag - Mixin
只要在 Class 标上 [Mixin]
并提供一个 public static function init(fbs:IFlexModuleFactory):void;
那麽当所有的 RSL 载入完成之后,Application 初始化之前
SystemManager 会自动呼叫所有 Mixin Class 的 init 方法

这主要是给一些全域的 Manager Class 作一些初始化的动作
e.g. EffectManager、StyleManager、ActiveWindowManager、...
但是它仍无法改变 SystemManager, RSL 的行为

Mixin Class:

 
package {
 import mx.core.IFlexModuleFactory;
 
 [Mixin]
 public class MixinClass {
  public static function init(fbs:IFlexModuleFactory):void{
   trace("MixinClass.init();", fbs);
  }
 }
}

3. 覆写 Flex 提供的 SystemManager

Flex SystemManager 相当于 Flash 的 Document Class
是整个 SWF 中最早能够开始执行程式的地方
由于整个 Flex Framework 需要精确的控制初始化程序
Flex 将这部分功能包成一个黑盒子,不让开发者去修改它
但是总会有些情况,不得已还是需要去 Hack SystemManager

以下就介绍一下如何 Hack SystemManager

一般实际使用到是 mx.managers.SystemManager 的 sub class 而已
是由 Flex Compiler 动态依据 Flex Project 设定与组件的使用情况而产生的

可以使用 Flex 编译命令参数 -keep=true
就会将自动产生的 SystemManager 原始码保留下来
档名类似这样 _main_mx_managers_SystemManager-generated.as

Flex 4 SystemManager 例子:

 
package {
 import flash.display.LoaderInfo;
 import flash.text.Font;
 import flash.text.TextFormat;
 import flash.text.engine.TextBlock;
 import flash.text.engine.TextLine;
 import flash.system.ApplicationDomain;
 import flash.system.Security
 import flash.utils.Dictionary;
 import flash.utils.getDefinitionByName;
 import flashx.textLayout.compose.ISWFContext;
 import mx.core.IFlexModule;
 import mx.core.IFlexModuleFactory;
 import mx.preloaders.DownloadProgressBar;
 import mx.preloaders.SparkDownloadProgressBar;
 import mx.core.FlexVersion;
 import mx.managers.SystemManager;
 
 public class _main_mx_managers_SystemManager
    extends SystemManager implements IFlexModuleFactory, ISWFContext {
  // Cause the CrossDomainRSLItem class to be linked into this application.
  import mx.core.CrossDomainRSLItem;
  CrossDomainRSLItem;
 
  public function _main_mx_managers_SystemManager() {
   super();
  }
 
  override public function callInContext(fn:Function, thisArg:Object, argArray:Array, returns:Boolean = true):* {
   if (returns)
    return fn.apply(thisArg, argArray);
   else
    fn.apply(thisArg, argArray);
  }
 
  override public function create(... params):Object {
   if (params.length > 0 && !(params[0] is String))
    return super.create.apply(this, params);
   var mainClassName:String = params.length == 0 ? "main" : String(params[0]);
   var mainClass:Class = Class(getDefinitionByName(mainClassName));
   if (!mainClass)
    return null;
   var instance:Object = new mainClass();
   if (instance is IFlexModule)
    (IFlexModule(instance)).moduleFactory = this;
   return instance;
  }
 
  override public function info():Object {
   return {cdRsls: [
     {"rsls": ["osmf_flex.4.0.0.13495.swf"], "policyFiles": [""], "digests": [""], "types": ["SHA-256"], "isSigned": [false]},
     {"rsls": ["textLayout_1.1.0.604.swf"], "policyFiles": [""], "digests": [""], "types": ["SHA-256"], "isSigned": [false]},
     {"rsls": ["framework_4.1.0.16076.swf"], "policyFiles": [""], "digests": [""], "types": ["SHA-256"], "isSigned": [false]},
     {"rsls": ["rpc_4.1.0.16076.swf"], "policyFiles": [""], "digests": [""], "types": ["SHA-256"], "isSigned": [false]},
     {"rsls": ["spark_4.1.0.16076.swf"], "policyFiles": [""], "digests": [""], "types": ["SHA-256"], "isSigned": [false]},
     {"rsls": ["sparkskins_4.1.0.16076.swf"], "policyFiles": [""], "digests": [""], "types": ["SHA-256"], "isSigned": [false]}],
    compiledLocales: ["en_US"],
    compiledResourceBundleNames: ["components", "core", "effects", "layout", "skins", "styles"],
    currentDomain: ApplicationDomain.currentDomain,
    mainClassName: "main",
    mixins: ["_main_FlexInit", "_main_Styles"],
    preloader: SparkDownloadProgressBar}
  }
 
  /**
   *  @private
   */
  private var _preloadedRSLs:Dictionary; // key: LoaderInfo, value: RSL URL
 
  /**
   *  The RSLs loaded by this system manager before the application
   *  starts. RSLs loaded by the application are not included in this list.
   */
  override public function get preloadedRSLs():Dictionary {
   if (_preloadedRSLs == null)
    _preloadedRSLs = new Dictionary(true);
   return _preloadedRSLs;
  }
 
  /**
   *  Calls Security.allowDomain() for the SWF associated with this IFlexModuleFactory
   *  plus all the SWFs assocatiated with RSLs preLoaded by this IFlexModuleFactory.
   *
   */
  override public function allowDomain(... domains):void {
   Security.allowDomain(domains);
   for (var loaderInfo:Object in _preloadedRSLs) {
    if (loaderInfo.content && ("allowDomainInRSL" in loaderInfo.content)) {
     loaderInfo.content["allowDomainInRSL"](domains);
    }
   }
  }
 
  /**
   *  Calls Security.allowInsecureDomain() for the SWF associated with this IFlexModuleFactory
   *  plus all the SWFs assocatiated with RSLs preLoaded by this IFlexModuleFactory.
   */
  override public function allowInsecureDomain(... domains):void {
   Security.allowInsecureDomain(domains);
   for (var loaderInfo:Object in _preloadedRSLs) {
    if (loaderInfo.content && ("allowInsecureDomainInRSL" in loaderInfo.content)) {
     loaderInfo.content["allowInsecureDomainInRSL"](domains);
    }
   }
  }
 }
}

SystemManager 裡面的 function 几乎不太会变动
会变动的主要是初始化需要用到的 info 资讯
e.g. RSLs、Locales、Mixins、Preloader、Main Class Name、Resource Bundle Names

样板有了,接下来是想办法覆写 Flex 内自动产生的 SystemManager
记得以前提到过的 Frame Metadata Tag 吗?

Multiple Frames Flex Application
Flex Metadata Tag - Frame FactoryClass

在主要的 Application 内加上 Metadata Tag
factoryClass 指定到你自己的 SystemManager Class

 
<fx:Metadata>
 [Frame(factoryClass="SysManager")]
</fx:Metadata>

一开始不知道怎样写 SystemManager 可以用 Flex 自动产生的程式码来改
需要特别注意的是,一旦决定要 Hack SystemManager
上述那些 info 资讯的维护工作就落到开发者的身上了!
不过事情也没有那麽困难
只要拿掉 Frame Metadata Tag 让 Flex Compiler 重新产生一次标准的 SystemManager
再拿来更新就好了~

相关连结:
观察 Flex SystemManager 初始化步骤
Paul Taylor - Understanding the Flex SystemManager
Multiple Frames Flex Application
Flex Metadata Tag - Frame FactoryClass bustardcelly - Flex 4: Suspending the first frame

转载请注明出处 http://ticore.blogspot.com/2010/08/call-prior-to-app-preinitialize.html

smithfox | Tuesday 08 March 2011 at 9:54 pm | | UI       

One comment

Louis Vuitton iPhone 6S Cases

A Weibo user has posted a Geekbench test screenshot for the new Exynos 8890 processor, which is currently codenamed M1 Mongoose. According to it, the chip is clocked at 2.3GHz and scored 2294 in single-core tests and almost 7000 in the multi-treaded Geekbench test .

Louis Vuitton iPhone 6S Cases, (URL) - 08-10-’15 20:42
(optional field)
(optional field)
为阻止垃圾广告, 请在提交评论前, 回答一个简单问题(Please answer an simple question)
Remember personal info?
Notify
Small print: All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.