ランタイム共有ライブラリを調べる
2011 年 5月 27 日 金曜日 kosukeFlashには「ランタイム共有ライブラリ(RSL)」という機能がある。
これはAS2のころからある機能でSWFの実行時にあるSWFがもつライブラリを他のSWFから利用するもの。
たとえば、A.swfでもB.swfでも利用するシンボルをShare.swfでRSLとして登録し、実行時に参照する。
するとA.swfとB.swfは自身のライブラリに同じシンボルのデータを持つ必要がなくなり、結果的にファイル容量が軽量化しダウンロードにかかる時間が短縮されたり、一意に修正をすることが出来たりするわけです。
便利そうな機能なのだけど、これが以外に使われない。RSLにすることで、(単一ファイルではありえない)読込みエラーなどが発生する機会が増えるなど構造的なデメリットもあるのだけど、一番の理由は読込みのタイミングがうまく制御できないからではないかと思っている。制御に関してはっきり挙動がわかる資料が無かった。最近は事情が変わってきて、RSLを進化させFlashPlayerにキャッシュするアドビ公式のランタイム共有ライブラリとでも言おうか。符号付きRSLであるSWZ形式のファイルが登場しRSL読込み用のクラスなども実装されてきた。
しかし、昔RSLを試したことあるけど…って方は鼻っからRSL使い物になる?と疑念もあってあまり関心がなかったりしないだろうか。(←早い話、僕。)そこで実際仕事で使いたかったって事情もあり調べてみた。
例として下のような、フチあり写真のようなシンボルがあり、このシンボルをRSLとして他のSWFから使うものとします。
ランタイム共有用に書き出しをチェックして、SWFを書き出します。SWFはShare.swfとしました。
RSLを利用する側のRSLTest1.flaではRSLの読込みを設定します。挿入→新規シンボルで空のシンボルを作り、ランタイム共有用に読込みをチェック。URLにShare.swfを指定します。(今回の場合、RSLTest1.flaを書き出したSWFとShare.swfは同じディレクトリに配置します。)
ここでは「いいえ」で。
タイムラインに適当に配置してみる。
パブリッシュ。
これでRSLに書き出したシンボルを読込み、表示するまでの確認ができました。
今はタイムラインに配置していますがクラスベースで開発する時は、通常インスタンスはスクリプトで制御して表示します。そこでタイムラインに配置したシンボルはすべて削除してドキュメントクラスからRSLを使う場合の検証をしました。
package rsl{ import flash.display.MovieClip; import flash.events.Event; import flash.events.ProgressEvent; import share.PhotoTemplate; public class RSLTest1 extends MovieClip{ public function RSLTest1(){ loaderInfo.addEventListener( Event.OPEN, onOpen ); loaderInfo.addEventListener( ProgressEvent.PROGRESS, onProgress ); loaderInfo.addEventListener( Event.INIT, onInit ); loaderInfo.addEventListener( Event.COMPLETE, onComplete ); } private function onOpen(e:Event):void{ trace("RSLTest1 OPEN:", loaderInfo.bytesLoaded, loaderInfo.bytesTotal ); } private function onProgress(e:ProgressEvent):void{ trace("RSLTest1 PROGRESS:", e.bytesLoaded, e.bytesTotal ); } private function onInit( e:Event ):void{ trace( "RSLTest1 INIT:", loaderInfo.bytesLoaded, loaderInfo.bytesTotal ); var temp:PhotoTemplate = new PhotoTemplate(); addChild( temp ); } private function onComplete( e:Event ):void{ trace( "RSLTest1 COMPLETE:", loaderInfo.bytesLoaded, loaderInfo.bytesTotal ); } } } |
ドキュメントクラスのSWF(RSLTest1.swf)のloaderInfoを監視しアクセス可能(Event.INIT)となったらPhotoTemplateのインスタンスを生成し表示リストに加える。表示されましたか?この検証では表示されませんでした。
traceは以下になっています。
Safariの構成ファイルなど読込んでいるファイルが見えるもので確認するとわかるのですがそもそもShare.swfが読込まれていません。
ランタイム共有用に読込みのシンボルはActionScript用に書き出しがチェックできない為、タイムラインに配置なしだとコンパイルに含まれないのだと思われます。そこでPhotoTemplateを含むシンボルを生成してActionScript用に書き出しをチェックしてみます。
今度はShare.swfは読込まれ、PhotoTemplateのインスタンスも表示されました。
しかし、今回はtraceは妙な出力をしています。
ProgressEvent.PROGRESSとEvent.COMPLETEが返ってこない。
ちなみにActionScript用に書き出しをやめて、先ほどのタイムラインに配置した状態でこのドキュメントクラスを使った場合も、PhotoTemplateのインスタンスは表示されますがProgressEvent.PROGRESSとEvent.COMPLETEが返ってきません。
ここまでの様子をまとめると、ランタイム共有ライブラリが読込まれる場合、そのドキュメントクラスでは、
・ProgressEvent.PROGRESSとEvent.COMPLETEは返ってこない。
・Event.INIT以降、ランタイム共有ライブラリにアクセス可能。
・loaderInfoのbytesLoadedとbytesTotalに、ランタイム共有ライブラリのSWFのファイルの容量は含まれない。
ものと思われる。
とすると、Flashで開発する場合にランタイム共有ライブラリを使うなら、RSLを読込むSWF単体にそれぞれについては、初期化時のEvent.INITを起点に開発することさえ気をつければ問題なさそうに思います。
しかしこのままだとRSLTest1.swfはEvent.INITがくるまで何のアクションもなく待ち続けることになる。そこでRSLTest1.swfとShare.swfの読込みを管理する為のプリローダー(Preloader1.swf)を考えてみる。
まず、RSLの読込みに使えるクラスがある。
RSLPreloaderは、SWZも含めてRSLのプリロードを管理するクラス。
Preloader1.swfがShare.swfのRSLをライブラリに読込んでいると意味がないのでPreloader1.swfではRSLを利用しないこと。
ちなみにActionScript用に書き出しがない状態でRSLを読込んでいる場合(ドキュメントクラスを使った最初の検証の場合)、RSLTest1.swfでRSLPreloaderクラスを使ってローディングしてもうまくいく。
package rsl{ import fl.events.RSLErrorEvent; import fl.events.RSLEvent; import fl.rsl.RSLInfo; import fl.rsl.RSLPreloader; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.ProgressEvent; import flash.net.URLRequest; public class Preloader1 extends Sprite{ private var rslPreloader:RSLPreloader; private var loader:Loader; public function Preloader1(){ super(); rslPreloader = new RSLPreloader(); var info:RSLInfo = new RSLInfo(); info.addEntry( 'Share.swf' ); rslPreloader.addRSLInfo( info ); rslPreloader.addEventListener( RSLErrorEvent.RSL_LOAD_FAILED, onRslLoadFailed ); rslPreloader.addEventListener( RSLEvent.RSL_PROGRESS, onRslProgress ); rslPreloader.addEventListener( RSLEvent.RSL_LOAD_COMPLETE, onRslLoadComplete ); rslPreloader.start(); loader = new Loader(); addChild( loader ); loader.contentLoaderInfo.addEventListener( Event.OPEN, onOpen ); loader.contentLoaderInfo.addEventListener( ProgressEvent.PROGRESS, onProgress ); loader.contentLoaderInfo.addEventListener( Event.INIT, onInit ); loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onComplete ); loader.load( new URLRequest( "RSLTest1.swf" ) ); } private function onRslLoadFailed( e:RSLErrorEvent ):void{ trace( "RSL_LOAD_FAILED:" ); } private function onRslProgress( e:RSLEvent ):void{ trace( "RSL_PROGRESS:", e.bytesLoaded, e.bytesTotal ); } private function onRslLoadComplete( e:RSLEvent ):void{ trace( "RSL_LOAD_COMPLETE:", e.bytesLoaded, e.bytesTotal ); } private function onOpen(e:Event):void{ trace("Preloader1 OPEN:", loader.contentLoaderInfo.bytesLoaded, loader.contentLoaderInfo.bytesTotal ); } private function onProgress(e:ProgressEvent):void{ trace("Preloader1 PROGRESS:", e.bytesLoaded, e.bytesTotal ); } private function onInit(e:Event):void{ trace("Preloader1 INIT:", loader.contentLoaderInfo.bytesLoaded, loader.contentLoaderInfo.bytesTotal ); } private function onComplete(e:Event):void{ trace("Preloader1 COMPLETE:", loader.contentLoaderInfo.bytesLoaded, loader.contentLoaderInfo.bytesTotal ); } } } |
trace出力は以下だ。
Share.swfのプログレスが取得できていることと、RSLTest1.swfのプログレスも取得できていることが確認できる。
さらにRSLTest1.swf単体だと動かなかった、Event.COMPLETEも無事動いている。
RSLPreloaderは、APIドキュメントではランタイム10.1以上ってことなんだけどどうなんだろう。サンプルはPlayer 9書き出しにして、Player 9(9.0.47.0)で見てみましたが動いていますね。。。SWZとか完全に動かないよってことなのかな。
他にFlex SDKで、
PreloaderとDownloadProgressBar
を使う方法も試した。この方法でもうまく読込めます。
Preloader2.as
package rsl{ import fl.rsl.RSLInfo; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.ProgressEvent; import flash.net.URLRequest; import mx.preloaders.Preloader; /** RSLの読込みをFlexのPreloaderで行ってみる。 */ public class Preloader2 extends Sprite{ private var rslPreloader:Preloader private var info:RSLInfo private var loader:Loader; public function Preloader2(){ super(); rslPreloader = new Preloader(); addChild( rslPreloader ); rslPreloader.initialize( true, CustomProgressBar, 0x000000, 1, null, "", 1, 1, [ "Share.swf" ] ); loader = new Loader(); addChild( loader ); loader.contentLoaderInfo.addEventListener( Event.OPEN, onOpen ); loader.contentLoaderInfo.addEventListener( ProgressEvent.PROGRESS, onProgress ); loader.contentLoaderInfo.addEventListener( Event.INIT, onInit ); loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onComplete ); loader.load( new URLRequest( "RSLTest1.swf" ) ); } private function onOpen(e:Event):void{ trace("Preloader1 OPEN:", loader.contentLoaderInfo.bytesLoaded, loader.contentLoaderInfo.bytesTotal ); } private function onProgress(e:ProgressEvent):void{ trace("Preloader1 PROGRESS:", e.bytesLoaded, e.bytesTotal ); } private function onInit(e:Event):void{ trace("Preloader1 INIT:", loader.contentLoaderInfo.bytesLoaded, loader.contentLoaderInfo.bytesTotal ); } private function onComplete(e:Event):void{ trace("Preloader1 COMPLETE:", loader.contentLoaderInfo.bytesLoaded, loader.contentLoaderInfo.bytesTotal ); } } } |
Preloaderから利用するProgressBarを用意。DownloadProgressBarを継承して各メソッドを上書きすればよい。
package rsl{ import mx.events.RSLEvent; import mx.preloaders.DownloadProgressBar; public class CustomProgressBar extends DownloadProgressBar{ public function CustomProgressBar(){ super(); } protected override function rslProgressHandler(event:RSLEvent):void{ trace( "rslProgressHandler:", event.bytesLoaded, event.bytesTotal ); } protected override function rslCompleteHandler(event:RSLEvent):void{ trace( "rslCompleteHandler", event.bytesLoaded, event.bytesTotal ); } } } |
trace出力はこんな感じ。
一応、このプリローダーからRSLとRSLを使うSWFを読込む方法なら、読込みのタイミングを処理できるんじゃないかと思う。
一応としているのは、SWZでないRSL、つまりユーザーが自由につくれるRSLはプレイヤーにはキャッシュされない。キャッシュされるのはブラウザのキャッシュであるということ。この当たりを読むとわかる。
Flash Playerキャッシュの使用によるFlexアプリケーション性能の改善
フレームワーク RSL の使用
ってことはやっぱり上のプリローダーを使った場合も、RSLPreloaderを先に処理しても、RSLTest1.swfを読込んだ後、RSLTest1.swfがRSLをリクエストするんじゃないかと。実際Safariの構成ファイルを見ると2度Share.swfが読込まれているので。2回目はキャッシュを参照するから瞬間的に読込まれるものと思われるけど、キャッシュを消していたら読込みに時間がかかるんじゃないかなと思っている。これはもうしょうがないんじゃないかと思う。サイト全体としてキャッシュ消された時の対策までを考えるなら、あるSWFを読込む時、そのSWFがRSLを利用しているものならRSLPreloaderで毎回プリロードかけるとか、プログレス表示なしでいいならEvent.INITを待つとか…。やっぱり今もRSLを使うことで手間になることはあると思う。
さてそんなRSLですが調べるきっかけとなった状況がありました。僕が直面したのは仕事で16ファイルのSWFを作る時。この16ファイルには共通するシンボルがあるのだけれど、モック段階から進めて作っていく為、アップデートを重ねる度にシンボルを16のflaファイル変更しなくちゃいけない。この時はオーサタイム共有ライブラリにして対応したので差し替えは半自動的に行っていたのですが、それでも16ファイルパブリッシュするとかってばからしいじゃない。試行錯誤の段階においては。
この時は結局RSLは使わなかったのですが、今度同じような時があったらRSLが使えるか調べておこうと思いました。
Flashで作るならアプリケーションで素早くデザインが見える・作れるというのが利点なので、最後にこの利点を踏まえてRSLの使い方を自分なりにまとめておきたい。
この記事では最初にPhotoTemplateというシンボルをShare.swfに作り、RSLTest1.swfでは空のシンボルを作ってRSL読込みの設定をしましたが、空のシンボルである必要はありません。なので、サイズは固定されているけど、中身の要素やデザインは変わっていくなんて時には途中段階のデザインでシンボルにし、RSL読込みを設定、最新のデザインはRSLから読込まれるようにしておくという方法が便利かと思いました。
先ほど作ったPhotoTemplateシンボルを編集する。今回は「はい」として一旦、RSL読込み設定を解除。
その時点の仮デザインを入れる。入れ子のシンボルなどに使う場合、仮のデザインでも有無でこの後の作業の進み具合が全然違ってくるものです。
RSL読込みがはずれていますので再設定。
そのシンボルをステージにおいてパブリッシュしてみると、きちんとShare.swfが書き出しているRSLで表示されます。
iPhone アプリ・クリエイターズファイル[2011-2012]
2011 年 5月 23 日 月曜日 kosuke6月7日発売の「iPhone アプリ・クリエイターズファイル[2011-2012]」という書籍で取り上げていただきました。ありがとうございます。書籍の情報を頂きましたので掲載します。
「iPhone アプリ・クリエイターズファイル[2011-2012]」
著者:馬渡徹郎/ディーフォース株式会社
価格:1,985円(税込)
仕様:176ページ/フルカラー
刊行日:2011年6月7日
ISBN:978-4-7981-2359-2
日本発!iPhoneアプリ制作者厳選160組一挙掲載!
トップクリエイター10組が成功するアプリの秘訣、教えます。
本書は3部構成になっています。
Part1では、大ヒットアプリを生み出した制作者へのインタビューです。実際の制作者に「企画段階のコツ」「開発段階のコツ」「プロモーションのコツ」、さらに「売上」についてなど、読者が聞きたいところをお聞きします。
Part2では、人気アプリを生み出した制作者を厳選160組紹介します。
最後のPart3では、基本となる開発から公開の流れ、また企業向けに発注の流れ、さらに運営面でのポイントも解説します。
◎Part1「iPhoneアプリ制作者インタビュー」
~大ヒットアプリはこうして生まれた!~
・Junpei Wada 「FingerPiano」
・オトバンク 「朗読少女」
・パンカク 「LightBike」
・APPARE JAPAN 「FingerSports」
・物書堂 「大辞林」
・Soohyun Park & Hiroaki Sato 「カロリー管理」
・Art & Mobile 「ToyCamera」
・安田陽介 「カード類」
・美人時計 「美人時計」
・APPLIYA STUDIO 「赤ちゃん泣き止み音!」
◎Part2「iPhoneアプリ制作者リスト」
~厳選160組のアプリクリエイター紹介~
◎Part3「iPhoneアプリ制作のノウハウ」
~アプリの企画から運用サポートまで~
amazonでのご予約・ご購入はこちらから↓
http://www.amazon.co.jp/dp/4798123595/
—————-
制作者リストの他、有名どころアプリ作者のインタビューありアプリ制作のノウハウありと、ボリュームもあってお求めやすい価格なので、アプリの発注先を探されている方や最近のアプリ事情を手早く知るのに便利そうな書籍です。
ウチで開発したiPhoneアプリはAir for iOSやTitanium MobileといったWeb技術の応用で作っていまして若干異質かも。よろしければサイドバーに掲載しているアプリをお試しください。
Adobe CS5.5
2011 年 5月 20 日 金曜日 kosuke本日発売のAdobe CS5.5。早速インストール中。
去年CS5出たばかりで.5のアップデートに6万弱かぁ…。左の水筒ついてきた。
経費だし、どのみち買わざるえないので使い倒してもととる!
ドリとフラッシュのモバイルアプリ制作系新機能が楽しみといえば楽しみです。
神仏霊場巡拝の道
2011 年 5月 19 日 木曜日 kosuke神仏霊場巡拝の道公式サイトでトップページのFlashを作りました。
企画はbiotopsさま。デザイン、アートディレクション、HTMLは高澤氏によるもの。
僕はトップページFlashの実装を担当させていただきました。
神仏霊場巡拝の道
http://www.shinbutsureijou.jp/
Client:神仏霊場会
Production : biotops
ArtDirection&Design&HTML : Yuhei Takazawa.
Flash : KOSUKE,Nakamura.nipx
メンテナンス性を持たせるため一覧に使う画像は外部ファイルにしつつ、多数の外部ファイルを読込むことで負荷がかからないよう、ファイルを統合した設計にしています。
Canvasから画像書き出ししてTitaniumに渡す
2011 年 4月 21 日 木曜日 kosuketitaniumのWebViewに配置したcanvasに描いたイメージをファイルに保存する方法。
ユーザーにcanvasで何かを描かせたらそのデータをファイルに保存したいことも多いはず。作文メーカーを作った時に調べたところWebViewの中のcanvasとtitaniumでデータを受け渡す方法が2つありました。
1.htmlファイル(canvasタグを書いたhtmlファイル)のJavaScriptでTitanium.App.fireEventでイベントを送信しイベントオブジェクトにcanvasのデータを添付する。
2.titaniumのjsからWebViewのevalJSメソッドを使って、htmlファイルに書いたcanvasのデータをreturnするJavaScriptを実行する。
作文メーカーでは2の方法を使っています。
まず、canvasでイメージデータに変換するにはtoDataURL() メソッドを使います。
以下のページを参考にしました。
toDataURL() メソッド – Canvasリファレンス – HTML5.JP
一つ問題があります。
toDataURL();
の戻り値はbase64でエンコードされた文字列なのですが、その先頭にmimetypeが含まれるようです。
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABcIAAAQqCAYAAABk7.... |
titaniumでファイルに保存する場合、このmimetypeが後々問題になりますので、どこかの段階で削除します。今回はtoDataURL()を実行した直後にreplaceで文字列から削除することにしました。最初の,以前を削除して以下のようなデータに整形します。
iVBORw0KGgoAAAANSUhEUgAABcIAAAQqCAYAAABk7.... |
この処理をまとめたのが以下の関数です。
function output(){ var cvs = document.getElementById( "stage" ); var src = cvs.toDataURL("image/png").replace(/^.*,/,''); return src; } |
この関数をtitaniumから実行して戻り値をファイルに変換します。
データをデコードしてファイルに書き込めば完了です。デコードするときにmimeTypeがあるとうまくいかないので削除しておく必要があったという具合でした。
var result = webview.evalJS("output();"); var base64 = Titanium.Utils.base64decode(result); var file = Titanium.Filesystem.getFile( Titanium.Filesystem.tempDirectory, "_TEMP_.png" ); file.write( base64 ); |
Canvasに解像度を設定する
2011 年 4月 20 日 水曜日 kosuke先日リリースしたオリジナルアプリ作文メーカーでは、ユーザー操作で描く文字の描画にCanvasを使っています。
titanium mobileでは描画APIが標準で用意されていない為、WebViewをつかってCanvasで代用した形です。僕はCanvasを使うのはこれが初めてでしたので、実装をCanvasでなく正攻法でいって描画系のモジュールを使うなどでも同じように1からだったのですが、Canvasでもそれなりにパフォーマンスが出るようだし、やはり僕のようなWeb系のデベロッパー/デザイナーにはWebの技術を使ったほうが間違いや不安も少ないと思ったので。今回のは単純な使い方だったしね。
このCanvasを使うにあたって疑問がありました。Ratina Display(640×960)の機種と通常ディスプレイ(320×480)の機種で使いわける必要があるのか?具体的にはキャンバスのサイズはどちらに設定すればいいのか?という点。開発時点ではRatina Displayの確認環境がなかったので、かなり疑問でした。
もう一つ、今回はアプリで使うデータになるので、Canvasで描いたものをtitaniumに渡さなくてはいけない。これできるの?という点。
結果的にどちらも疑問は解消したのですが、初めてってこともあって右往左往と調べたりしたので2回に分けてメモしておきます。参考になる方もいるかもです。
とりあえず今回は前者の疑問、サイズの問題。これをCanvasに解像度を設定すると題して説明します。
iPhoneアプリ 作文メーカー
2011 年 4月 17 日 日曜日 kosukeRelish 2011SS Collection
2011 年 3月 3 日 木曜日 kosukeRelish 2011 Spring & Summer のスペシャルサイトでFlashをやらせていただきました。
サイトプロデュースはFICCさま。アートディレクションにnssgraphica.町田さん、デザインにnssgraphica.神村さんという布陣で、僕はFlashの実装を担当させていただきました。関係者のみなさまおつかれさまでした。
Relish 2011SS Collection
http://www.relish-style.net/
Production : FICC
ArtDirection : Munehiro Machida.nssgraphica
Design : Makoto Kamimura.nssgraphica
Flash : KOSUKE,Nakamura.nipx