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アプリはちゃんと動作しないかもしれません。