iPhoneアプリ YURAx2GIF

  • 2011 年 7月 19 日
  • kosuke

ホワイトボードをイメージしたiPhone用らくがきアプリ「YURAx2GIF」をリリースしました。
無料アプリです。特徴はtwitterアカウントがあれば書いた落書きをゆらめくGIFアニメーションにしてtwitpicにアップロードできること。さらにアップロードしたtwitpicのURLをtwitterに共有できます。

YURAx2GIF - nipx

このアプリはAdobe air for iOSで作りました。Flashでシンボルを作って、Flash BuilderのActionScript モバイルプロジェクトで組み上げた形。当初はair 2.6で書き出していたのだけど、途中でair 2.7がリリースされた為、公開しているアプリはair 2.7で書き出しています。air 2.7になってiOSでのパフォーマンスもいい感じです。やっとという感じですけどair 2.7なら内容によってはiOSでも結構使えるんじゃないかと思いました。

ランタイム共有ライブラリのさらなるローディング方法

  • 2011 年 5月 28 日
  • kosuke

Adobeのヘルプからもリンクが貼られているブログ記事で、Using a Custom Preloader Loop With TLF Textというエントリーを読みました。

TLFテキストは符号付きRSLが用意されていますが、独自のプリローダーで読込もうとするといろいろなエラーが出てうまく読込めません。
その対処法として、ActionScriptのクラスを書き出すフレームを2フレームにして、1フレーム目ではフレームスクリプトを記述し、RSLとSWF本体の読込みが完了したら2フレームに移動する方法が書かれています。1フレーム目にプリロードを持たせるってのは、昔からやってる人なら懐かしく思う方法なんじゃないでしょうか。

なるほど。そういう手もあるかと思いまして、前回のエントリでは、単体SWFでRSLを読込む時、Event.INITが発生するまで、SWF自身の容量を取得できませんでしたが、この方法ならいけるんじゃないかと。

しかも、先のページのサンプルだと、フレームスクリプトで、

this.addEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRSLComplete);

なんて記述があって、えぇ?!そんなところでRSLの進行具合取れるの?と驚いたりもします。
ということで試してみました。今度もまた入り組んでいてわかりにくいのですが。

1.SWZをカスタムプリローダーで読込んでエラーを確認
まずサンプルをそのまま試してみます。1フレームにTLFTextFieldを配置。

ひとまずエラーを確認する為、クラスを書き出すフレームは1のままでカスタムプリローダーを使う設定だけします。

パブリッシュ。Flash Player 10 & 10.1をターゲットにしました。ご覧のようなエラー出る。コンパイル段階でも警告が出てます。そして1フレームに配置したTLFTextFieldが表示されません。このエラーはプリローダーを利用しない「コードにマージ」をした場合はもとい、デフォルトのプリローダーSWFを使った時は発生せず、TLFTextFieldも表示されることを確認しています。つまり、このエラーはカスタムプリローダーを設定したとき特有のもの。

2.jeffkamerer.comのフレームスクリプトを入れて確認
次にjeffkamerer.comの方法でエラー解消を確認する。TLFTextFieldを2フレームに移動。

クラスを書き出すフレームを2に変更。

パブリッシュすると2フレームで無事TLFTextFieldが表示される。traceは以下の通り。

1:Frame Script Start
ProgressEvent.PROGRESS: 36092 36092
Event.COMPLETE: 36092 36092
RSLEvent.RSL_PROGRESS: 1208 186404
•
•
•
RSLEvent.RSL_PROGRESS: 186404 186404
RSLEvent.RSL_LOAD_COMPLETE: 0 0

SWF自身のProgressEvent.PROGRESSが取得できている。SWF自身の読込みが完了してからRSLEvent.RSL_PROGRESSが動き始めているように見えるけど、これはSWFの容量が小さいからで、容量を大きくして、ダウンロードのシュミレートで見るとProgressEvent.PROGRESSとRSLEvent.RSL_PROGRESSは平行して実行されています。

3.通常のRSLを加えてみる
SWZのTLFを読込む確認ができたので、ここにRSLの読込みを加えてみる。前回のエントリーで使った、写真の枠のシンボル、PhotoTemplateをRSLに書き出したShare.swfを使います。
まず、SWFのライブラリにPhotoTemplateをRSL読込み設定をする。そのシンボルを2フレームに配置しました。

これをパブリッシュすれば2フレームに移動した後、Share.swfのRSLが表示されると思ったのですがダメでパブリッシュするとエラー。

これなんだか意味不明なエラーなんですけど。エラーに関していえばこれに始まったことではなく他にも不思議なエラーいろいろ出ますので…。そもそもTLFが普通にカスタムプリローダーで読込めないって話自体、意味不明なわけでこの位で挫けていてはRSLは使えません。
ここはひとまず、2フレームに配置したPhotoTemplateのインスタンスを削除します。そして前回同様、PhotoTemplateを入れ子にしたシンボル(PhotoContainer)をつくりActionScriptに書き出すとします。さらにこのままだと2フレームにPhotoTemplateは表示されないので、2フレームのフレームスクリプトでインスタンスを表示させるスクリプトを加えました。

import share.PhotoTemplate;
 
var photo:PhotoTemplate = new PhotoTemplate();
photo.x	= 250;
photo.y	= 300;
addChild( photo );

これでパブリッシュすると、エラーはでないのですが正しく動かない。1フレームから動かない状態になる。ブラウザでみるとShare.swfも読込んでいるし、trace結果はEvent.COMPLETEもRSLEvent.RSL_LOAD_COMPLETEも動いているのでgotoAndStop(2)が動かないという状況。ちなみに2フレーム目にいれたフレームスクリプトはこの不具合に関係ありません。消しても同様だった為。
もうこのあたりから、何が仕様で、正しく動いているのか、バグなのか、こちらのエラーなのかわからなくなってくるのですが…。
ひとまず解決策として、入れ子にしたPhotoContainerのActionScript書き出しで「2フレーム目に書き出し」のチェックを外します。

パブリッシュすると、今度は2フレーム目まで動き、TLFTextFieldが表示されます。しかし、2フレーム目に書いたフレームスクリプトインスタンスを追加してもShare.swfのもつRSLが表示されません。ブラウザで確認してみるとShare.swfを読込んでいない状況です。

4.RSLPreloaderを加えてみる
3の結果からそれなら前回使ったRSLPreloaderを使ってあらかじめShare.swfを読込んだらどうだろうと思いました。
その前に気になることがあります。1フレームに書いた以下のフレームスクリプトでSWZの読込みはイベントとして取得できています。

addEventListener(RSLEvent.RSL_PROGRESS, onRSLProgress);
addEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRSLComplete);

だったら、通常のRSLも同じようにイベント取得できないか?
試しに3の状態からTLFTextFieldを削除して、1フレームにPhotoTemplateを配置してみたのですが…。表示はされるもののイベントは取得できずでした。また前回と同じでEvent.INITが発生するまでSWF自身の容量がわかりません。

更にPhotoContainerの「2フレーム目に書き出し」にチェックを入れた場合でも同様。この場合は2フレーム目に入らないのでShare.swfも読込まれないという状況です。

つまり、フレームスクリプトで書いた、

addEventListener(RSLEvent.RSL_PROGRESS, onRSLProgress);
addEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRSLComplete);

で取得できるのは、SWZの場合のみのようです。SWZはユーザーがローカルへのキャッシュを許可していない場合、フェイルオーバー RSLという通常のRSLが代替えで読込まれますがこのRSLは上記のイベントで取得できました。(ややこしい。)

なので、符号付きRSLもRSLも読込む場合、符号付きRSLのプリロードは上記のイベントで取得し、RSLはRSLPreloaderでプリロードするってことになるんですかね?ともあれRSLPreloaderを試してみます。

RSLPreloaderでShare.swfを読込む。読込みの完了がどういう順で起きるかはわからないので、RSLPreloaderの完了フラグとしてpreCompleteを追加し、swfComplete と rslComplete をあわせて3つのフラグが処理されたらフレーム2に移動させる。

import fl.events.RSLEvent;
import fl.rsl.RSLInfo;
import fl.rsl.RSLPreloader;
 
import flash.events.Event;
import flash.events.ProgressEvent;
 
trace( "1:Frame Script Start" );
stop();
 
var rslPreloader:RSLPreloader;
var info:RSLInfo
 
var swfComplete:Boolean = false;
var rslComplete:Boolean = false;
var preComplete:Boolean = false;
 
loaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
loaderInfo.addEventListener(Event.INIT, onInit);
loaderInfo.addEventListener(Event.COMPLETE, onComplete);
 
addEventListener(RSLEvent.RSL_PROGRESS, onRSLProgress);
addEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRSLComplete);
 
rslPreloader= new RSLPreloader();
info		= new RSLInfo();
info.addEntry( 'Share.swf' );
rslPreloader.addRSLInfo( info );
rslPreloader.addEventListener( RSLEvent.RSL_PROGRESS, onRslProgress );
rslPreloader.addEventListener( RSLEvent.RSL_LOAD_COMPLETE, onRslLoadComplete );
rslPreloader.start();
 
 
//SWFのロード確認リスナー
function onProgress(e:ProgressEvent):void{
	trace( "ProgressEvent.PROGRESS:", e.bytesLoaded, e.bytesTotal );
}
 
function onInit(e:Event):void{
	trace( "Event.INIT:", e.target.bytesLoaded, e.target.bytesTotal );
}
 
function onComplete(e:Event):void{
	trace( "Event.COMPLETE:", e.target.bytesLoaded, e.target.bytesTotal );
	loaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgress);
	loaderInfo.removeEventListener(Event.COMPLETE, onComplete);
	swfComplete = true;
	if(rslComplete && swfComplete && preComplete){
		gotoAndStop(2);
	}
}
 
//RSLのロード確認リスナー
function onRSLProgress(e:RSLEvent):void{
	trace( "RSLEvent.RSL_PROGRESS:", e.bytesLoaded, e.bytesTotal );
}
 
function onRSLComplete(e:RSLEvent):void{
	trace( "RSLEvent.RSL_LOAD_COMPLETE:", e.bytesLoaded, e.bytesTotal );
	removeEventListener(RSLEvent.RSL_PROGRESS, onRSLProgress);
	removeEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRSLComplete);
	rslComplete = true;
	if(rslComplete && swfComplete && preComplete){
		gotoAndStop(2);
	}
}
 
//RSLPreloaderのロード確認リスナー
function onRslProgress( e:RSLEvent ):void{
	trace( "RSLPreloader RSL_PROGRESS:", e.bytesLoaded, e.bytesTotal );
}
 
function onRslLoadComplete( e:RSLEvent ):void{
	rslPreloader.removeEventListener(RSLEvent.RSL_PROGRESS, onRslProgress);
	rslPreloader.removeEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRslLoadComplete);
	trace( "RSLPreloader RSL_LOAD_COMPLETE:", e.bytesLoaded, e.bytesTotal );
	preComplete = true;
	if(rslComplete && swfComplete && preComplete){
		gotoAndStop(2);
	}
}

これでやっと期待どおりに動いた。

traceを確認すると以下でした。

1:Frame Script Start
Event.INIT: 17931 17931
ProgressEvent.PROGRESS: 17931 17931
Event.COMPLETE: 17931 17931
RSLPreloader RSL_PROGRESS: 1024 3613
・
・
RSLPreloader RSL_PROGRESS: 3613 3613
RSLPreloader RSL_LOAD_COMPLETE: 0 0
RSLEvent.RSL_PROGRESS: 1208 186404
・
・
RSLEvent.RSL_LOAD_COMPLETE: 0 0

Progressが順番に並んで発生していますが、これもダウンロードのシュミレートで確認するとバラバラに発生するので、読込みが完了する順番は必ずしも一定ではありません。

さて、これで完璧と思ったのですが落とし穴が他にもありました。
それはドキュメントクラス。この状態でドキュメントクラスを設定しました。内容は以下。

package sample{
 
	import flash.display.MovieClip;
 
	public class Sample2 extends MovieClip{
 
		public function Sample2(){
			trace( "Document Class Sample1" );
		}
 
	}
}

コンストラクタでトレースを吐いている以外、何もしていません。
さて、この「クラスを書き出すフレーム」を2フレームに設定したflaファイルで、ドキュメントクラスを設定した場合、コンストラクタのトレースはいつ実行されるでしょうか?

確認してみると、一番最初。1フレームのフレームスクリプトでtraceしている「1:Frame Script Start」よりも前に実行されます。
そのドキュメントのコンストラクタってことだから、冷静に考えるとこれでいいような気もしますが、「クラスを書き出すフレーム」との整合性がわかりにくいです。しかも、このドキュメントクラスを設定すると、これまた正しく2フレームに移動しません…。
traceを確認すると

rslPreloader.addEventListener( RSLEvent.RSL_PROGRESS, onRslProgress );
addEventListener(RSLEvent.RSL_LOAD_COMPLETE, onRSLComplete);

のイベントのRSLEvent.RSL_LOAD_COMPLETEが戻ってきていないのでこれが原因のようなのですが、解決策的にはRSLEvent.RSL_PROGRESSの完了で判定してもダメで、(VerifyError: Error #1014: クラス flashx.textLayout.container::TextContainerManager が見つかりません。となる。)
今のところ解決策的にはドキュメントクラスを使わず、コンテナとなるインスタンスを2フレームで追加する方法。

こんな感じで、コンテナとなるクラスを作って、

package sample{
 
	import flash.display.Sprite;
	import share.PhotoTemplate;
 
	/** 2フレームで追加されコンテナとなるクラス。 */
	public class Container extends Sprite{
 
		public function Container(){
			var photo:PhotoTemplate = new PhotoTemplate();
			photo.x	= 250;
			photo.y	= 300;
			addChild( photo );
		}
	}
}

2フレームのフレームスクリプトで配置する。

import sample.Container;
 
var container = new Container();
addChild( container );

これだとうまくいっているけど…。僕はよくProgressionを使っているので、ドキュメントクラスを使えないのはいたいな。
やはり一筋なわではいかないか。RSL。

蛇足ですが、キャッシュされたSWZは、それぞれ以下にあります。

Windows 95/98/ME/2000/XP
C:¥Documents and Settings¥user_name¥Application Data¥Adobe¥Flash Player¥AssetCache¥

Windows Vista
C:¥Users¥user_name¥AppData¥Roaming¥Adobe¥Flash Player¥AssetCache¥

Linux
/home/user_name/.adobe/Flash_Player/AssetCache/

Mac OSX
/Users/user_name/Library/Cache/Adobe/Flash Player/AssetCache/

キャッシュを消して読込みを確認するには上記ディレクトリの中のファイルを削除します。
またSWZではなく、フェイルオーバー RSLを試すには、
Adobe – Flash Player : 設定マネージャー – グローバルストレージ設定パネル
で、共通のFlashコンポーネントを格納して、ダウンロード回数を削減しますのチェックを外したり、記憶容量を0にするなどすると確認出来ました。

ランタイム共有ライブラリを調べる

  • 2011 年 5月 27 日
  • kosuke

Flashには「ランタイム共有ライブラリ(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

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で、
PreloaderDownloadProgressBar
を使う方法も試した。この方法でもうまく読込めます。

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 日
  • kosuke

6月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 日
  • kosuke

titaniumの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 日
  • kosuke

手書きで作文を書くアプリを作りました。作文を原稿用紙の画像ファイルに書き出せます。「ひらがなれんしゅうちょう」や「カタカナれんしゅうちょう」で文字を練習して作文を書こう。

作文メーカー - nipx





無料版もあります。無料版は原稿用紙にニピクロゴの透かしが入る以外、有料版と同じです。

作文メーカー FREE版

作文メーカー FREE版 - nipx

無料版は原稿用紙にロゴの透かしが入るよ。

Relish 2011SS Collection

  • 2011 年 3月 3 日
  • kosuke

Relish 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

@