FlashのLoaderで、Flexで作ったSWFをロードする

ファイルサイズがでかいとか、自社鯖が非力だとかいう理由で、CDNからSWFを配信したいんだけども、SWFの起動元ドメインは自社ドメインにしたいよって場合があります。自社ドメインに格納されたSharedObject読むときとか。

で、そういう場合は、ちっちゃいローダのSWFを準備して自社鯖で配信し、ローダからCDN上のSWFを読み込むという手が考えられます。でも、この方法にはちょっと問題があって、ローダをFlexで作ると、SWFのサイズが140KBぐらいになっちゃうのです。これはでかい。

似たようなローダをFlashで作るとローダSWFは1.2KBぐらい。なのでぜひローダはFlashで作りたいのだけど、ここでもまた問題が。ローダが読み込んだFlexアプリの表示サイズがおかしくなってしまうのです。Flexアプリの表示サイズが固定なら大丈夫なこともありますが、embedタグのサイズピッタリに張り付くアプリ(mxmlでアプリの縦横サイズを100%に指定してるやつ)だと、表示サイズが全く広がらない。ブラウザサイズいっぱいに表示されるFlexアプリだと、表示ムチャクチャになります。

しょうがないのでembedタグのサイズぴったりに広がるタイプのFlexアプリをロードするために、Flash用のコード書いてみました。stageのリサイズイベント拾って、無理やりApplicationをリサイズします。Flex SDK 3.5で作ったSWFの読み込みしか試してないので、Flex 4だと動かないかも。

package {
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;

    import flash.display.Loader;
    import flash.display.MovieClip;
    import flash.display.DisplayObject;
    import flash.display.DisplayObjectContainer;
    import flash.net.URLRequest;

    import flash.system.ApplicationDomain;
    import flash.system.SecurityDomain;
    import flash.system.Security;
    import flash.system.LoaderContext;
    import flash.events.Event;

    public class ThinFlexLoader extends MovieClip {

        public static var SWF_URL:String = "flex_app.swf"; // 読み込みたいFlexアプリを相対orフルパスで指定

        private var _loader:Loader = new Loader();
        private var _flexSystemManager:DisplayObject;
        private var _flexApplication:DisplayObject;

        public function ThinFlexLoader() {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            stage.addChild(_loader);
            addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        }

        private function onAddedToStage(event:Event):void {
            removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);

            _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);

            if (Security.sandboxType == Security.REMOTE) {
                _loader.load(new URLRequest(SWF_URL), new LoaderContext(true, ApplicationDomain.currentDomain, SecurityDomain.currentDomain));
            } else {
                _loader.load(new URLRequest(SWF_URL), new LoaderContext(true, ApplicationDomain.currentDomain));
            }
        }

        private function onComplete(event:Event):void {
            _loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete);
            _flexSystemManager = _loader.getChildAt(0);
	    stage.addChildAt(_flexSystemManager,0); // 念のためSystemManagerをstageの最初の子にする。
            stage.removeChild(_loader);
            _flexSystemManager.addEventListener("applicationComplete",onApplicationComplete);
        }
        
        private function onApplicationComplete(event:Event):void {
            _flexApplication = _flexSystemManager["application"] as DisplayObject;
            _flexApplication.width = stage.stageWidth;
            _flexApplication.height = stage.stageHeight;
            stage.addEventListener(Event.RESIZE, onResize);
        }

        private function onResize(event:Event):void {
            _flexApplication.width = stage.stageWidth;
            _flexApplication.height = stage.stageHeight;
        }
        
    }

}

本当はstageのリサイズにFlexのSystemManagerも追従させたかったのですが、やってみても、なぜかうまくいかなかったのであきらめました。SystemManagerのリサイズを拾うFlexアプリはちゃんと動作しないかもしれません。