アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

Flashコンテンツのスマホアプリ(iOS/Android)への移植手法に関して

あけましておめでとうございます、鴨田です。

今年一本目のアシアルブログの投稿になります。
今年もどうぞよろしくお願いいたします。

さて、昨年末に弊社で開発を行った案件として、
FlashコンテンツのiOS/Androidアプリ移植というのがありました。

Flashの移植では、いろいろと手法はあると思いますが、
今回は純粋にネイティブアプリに移植しました。

開発手法の選定や開発中の試行錯誤について、お話ししたいと思います。



手法の決定に関して



まず、元のFLAファイルが一つだけではなく、
複数のFLAファイルに分かれていたこと、
元のFLAファイルが存在しないコンテンツが存在していた、
ActionScriptがそもそも2.0だった、などのことから、
Abobe AIR for iOS/Androidを使うことはありませんでした。

いろいろな情報を集めた限りでは、
AIRで出来るのであれば、AIRを使うのがいいのかなと思います。

その次に考えたことは、CreateJSを使うことです。
弊社でも実績があるため、結構有力な方法として考えていました。

CreateJS

試しにいくつかのコンテンツでCreateJSを使用して、
HTML5に書き出してみました。

結果として、うまくいくコンテンツもあれば、
オブジェクト数が多すぎて、アプリ内のWebViewではもちろんのこと、
Androidの標準ブラウザにおいても、
処理が重すぎてまともに動作しないものもありました。
(PCのブラウザではサクサク動くのに・・・)

ということで、最終的にはネイティブアプリで作成することとしました。



ネイティブアプリで使う素材を準備する



まず、元のFLASHのメニュー部分などは、画角が合わないため、
スマートフォン端末用にレイアウトの組み直しと、
一部デザインの修正を行いました。

単純にムービーを再生するだけのコンテンツに関しては、
「Swivel」という、SWFを動画変換できるフリーソフトを使用して、
H264書き出しを行いました。
ActionScriptまで読み取って変換してくれるいいソフトです。

Swivel

あとは、タップ時などにアニメーションを行うというのが、
元になったコンテンツで主に使用されるアクションだったので、
Flashから各オブジェクトを連番PNGの形で書き出して、
ものによってはスプライト化、あるいは、ムービー化しました。



ネイティブアプリで実装する



前述したように、基本的にはオブジェクトがアニメーションするというのが、
アプリのコンテンツに共通した内容であったため、
連番PNGあるいはスプライト画像を使用して、
パラパラアニメーションを行うというのが主な実装内容でした。

これだけを聞くとすぐに実装できそうです。
事実、iOSでは特に問題なく、実装が完了したのですが、
Androidに関しては、OSバージョン、機種依存の問題が多々あり、
思うように実装が進みませんでした。

そのほとんどはAndroidのバグなので、
実装方法が悪いというわけでもなく、
どうにかこうにかやり過ごしましたが、
いろいろと煮え湯を飲まされました。

特に悩まされたこととして、
VideoViewとSurfaceViewの重なり順がおかしくなる、
というのがあるのですが、結局解決しなかったため、
重ならないようにレイアウト変更を行うことで避けたりしました。




FlashiOS/Androidへの移植関連で検索しても、最近の記事が見あたらないので、
もしかしたら、最近はあまり移植が行われていない可能性もありますが、
そのような案件があれば、参考にしてもらえたらと思います。。

まとめとしては、
ネイティブで開発する場合はクロスプラットフォームという意味では難がありますが、
いろいろと柔軟に対応できるのはとても魅力だと思います。

AIRで問題ないコンテンツであれば、もちろんAIRが第一選択になります。
クロスプラットフォームという意味でも問題ありませんし、
最近のAIRであれば、ネイティブ機能を使うことも問題ないようです。

今はまだ実用的とは言い難いですが、CreateJSなどを使用して、
HTML5化するというのも、今後は十分視野に入ると思いますし、
そうなって欲しいと願っています。

「Felica交換日記」 最優秀賞受賞!@Felica&AIR/Flashアプリケーションコンテスト

Felica&AIR/Flashアプリケーションコンテストにて、「最優秀賞」を受賞いたしました!!

Felica交換日記とは、FeliCaを用いた交換日記アプリです。

もともとFeliCaは個人1人で使うものですが、それを数人でシェアすると何かできないかな?という発想から、書き込み時に使用したFeliCaがないと、読んだり返信したりできないという交換日記アプリの構想に至りました。

まずAIRアプリを起動すると、交換日記のブック表紙が表示されます。



FeliCa(種類は問いません)を端末に載せると、日記帳がパラパラと開き、最新の書き込みページが表示されます。



右側のページに日記を書き込んだ後、FeliCaを端末からはずすと、自動的に記入した内容がサーバーに保存されます。



後は、このFeliCaを交換相手に渡すだけで、誰にも知られない交換日記のできあがり!

たとえばシール型のFeliCaを実際の手帳に貼り付けたりして、秘密のメッセージを相手に伝えることも可能です。

Felica&AIR/Flashアプリケーションコンテストの結果発表内容については、
ソニー株式会社が運営する「Felica&AIR/Flashアプリケーションコンテスト、コンテスト結果発表ページ」をご参照いただけたらと思います。

ダウンロードは、コンテスト Entry No.10 「Felica交換日記」(AIR): SDK for AIR/Flash ブログからお願いします。

是非お試しあれ!!

--
【参考1:Felicaとは?】
FeliCaフェリカ)とは、ソニー株式会社が開発した非接触ICカード技術方式です。現在は、携帯電話や電子カードに内蔵され、様々なシーンで使用されています。コイン型・シール型化したFeliCa Liteや、無線インターフェースモジュールのFeliCa Plug、リング型のモジュールの登場により、これからのさらなる発展が期待されています。

【参考2:FeliCa+Webシステムでできること】
FeliCaを使ったWebシステム設計例として、
例えば、FeliCaリーダー/ライターにかざされたFeliCa端末から情報を引出し、その情報をWebシステムとやりとりすることで、FeliCaを媒介としたサービスを利用することができます。

【Flex3】「Flex3の、こんなときどうするの??」

こんにちは、最近モールス信号に興味深々の橋本です。

さて、今回は前回の「AS3のこんなときどうするの?」の続編で、

Flex3のこんなときどうする?」をテーマに、また思いついたところを適当に書いていきたいと思います。

アサインされてるプロジェクトを進める中で発見したものばかりなので、結構偏りがあるかもしれませんが、そこはご了承くださいませ。。。

では、どぞー。

1. スクリプトの中で値をバインドしたい

Q. mxmlの中で値をバインドするときには、バインドしたい変数をmxmlの中で{}で囲み、対象の変数に、[Bindable]タグをつければオッケーなんだけど、スクリプトの中で、値をバインドさせたいときはどうするの??

A. BindingUtilsクラスを使いましょう。
BindingUtils.bindProperty()を使うことで、プロパティ同士をバインドさせることができます。



var textInput:TextInput = new TextInput();
addChild(textInput);
				
var label:Label = new Label();
addChild(label);

BindingUtils.bindProperty(label, "text", textInput, "text");


bindSetterメソッドを使うことで、対象の変数が変化したときに、特定のメソッドを呼び出すこともできますよ。



<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" minWidth="1024" minHeight="768"
				creationComplete="application1_creationCompleteHandler(event)"
				>
	<mx:TextInput id="textInput"/>
	<mx:Label id="hoge"/>
	<mx:Script>
		<![CDATA[
			import mx.binding.utils.BindingUtils;
			import mx.controls.Label;
			import mx.controls.TextInput;
			import mx.events.FlexEvent;
			

			protected function application1_creationCompleteHandler(event:FlexEvent):void
			{
				BindingUtils.bindSetter(toUpperCase, this.textInput, "text");
			}
			
			private function toUpperCase(str:String):void
			{
				this.hoge.text = str.toUpperCase();
			}
		]]>
	</mx:Script>
</mx:Application>


2. 自分で作ったクラスのプロパティをバインドの対象にしたい

Q. 自分で作成したクラス内のプロパティをバインドの対象にしたい。でも、呼び出し元で[Bindable]タグをつけるわけにもいかないし、BindingUtils使おうと思っても、対象外って怒られるし、どうするの??

A. 自分で作成したクラス内の変数のセッター内で、イベントをdispatch。Bindableタグの中で、そのイベントを指定するとバインドの対象にできますよ。
こんな感じです。



var hoge:String;

//セッターの中で、設定したイベントをdispatch。Bindableタグで、イベントを指定
[Bindable(event="hogeChange")] 
public function set hoge(value:String):void
{
	dispatchEvent(new Event("hogeChange"));
	hoge = value; 
}


3. 独自イベントをmxmlの選択項目にいれたい

Q. 自分でカスタムしたコンポーネントを呼び出すときに、独自イベントをmxmlで指定したいんだけど、どうするの??

A. コンポーネント内のMetadataタグの中にイベント名を記載しておきましょう。そうすることで、後からmxml上で使うことができます。



<mx:Metadata>
	[Event(name="hoge",type="flash.events.Event")]
</mx:Metadata>


4. DataGridの背景色を変更したい

Q. DataGridの背景色をセル毎に変えたいんだけど、どうするの??

A. DataGridColumnのitemRendererのbackgroundプロパティをtrueにして、backgroundColorを設定することで変更できますよー。



<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" minWidth="1024" minHeight="768"
				xmlns:components="components.*"
				creationComplete="application1_creationCompleteHandler(event)"
				>
	<mx:DataGrid dataProvider="{dataList}"
				 width="100%"
				 height="100%"
				 >
		<mx:columns>
			<mx:DataGridColumn headerText="hoge" dataField="data" itemRenderer="components.Hoge"/>
		</mx:columns>
	</mx:DataGrid>
	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import mx.events.FlexEvent;

			[Bindable]
			private var dataList:ArrayCollection;
			
			protected function application1_creationCompleteHandler(event:FlexEvent):void
			{
				var arr:ArrayCollection = new ArrayCollection();
				for (var i:int = 0; i < 100; i++)
				{
					var obj:Object =
						{
							data: i
						}
					;
					
					arr.addItem(obj);
				}
				
				dataList = arr;
			}

		]]>
	</mx:Script>
</mx:Application>


itemRenderer用のクラス


package components
{
	import mx.controls.dataGridClasses.DataGridItemRenderer;
	
	public class Hoge extends DataGridItemRenderer
	{
		
		public function Hoge()
		{
			super();
			
			this.background = true;
			// ランダムの色を入れる
			this.backgroundColor = Math.random() * 0xFFFFFF;
		}
	}
}


5. DataGridに文字列以外のものを表示したい

Q. DataGridに、ボタンとか画像とかチェックボックスとか、その他諸々を表示したいんだけど、どうするの??

A. DataGridColumnのitemRendererに、表示したいコンポーネントのクラスを指定することで変更することができますよー。
mxmlで指定するときには、一つ前のサンプルの中でやっているような感じで、クラス名を指定してやればオッケーです。
スクリプトで指定するときには、ClassFactoryクラスのインスタンスを指定してやればオッケーです。



var column:DataGridColumn = new DataGridColumn();
column.itemRenderer = new ClassFactory(Hoge);


6. ツリーに文字列以外のものを表示したい

Q. ツリーにボタンとか画像とかチェックボックスとか、その他諸々を表示したいんだけど、どうするの??

A. DataGridのときと同様に、itemRendererを指定することで可能です。
ただ、チェックボックスを表示するときは要注意。DataGridやTreeなどの、ListベースのコンポーネントのitemRendererは内部で使いまわされるので、チェックした状態を保持しておく機構が必要です。

以下の例では、TreeのdataProviderに指定しているXMLに、selectedというAttributeを持たせて、それを変更することによって、チェック状態を保持しています。



<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" minWidth="1024" minHeight="768"
				xmlns:components="components.*"
				>
	<mx:Tree itemRenderer="components.Hoge" dataProvider="{xml}" width="100" labelField="@value"/>
	<mx:Script>
		<![CDATA[
			[Bindable]
			private var xml:XMLList = XML(
				<root>
					<node selected="false" value="1"/>
					<node selected="false" value="2"/>
					<node selected="false" value="3"/>
					<node selected="false" value="4"/>
					<node selected="false" value="5"/>
					<node selected="false" value="6"/>
					<node selected="false" value="7"/>
					<node selected="false" value="8"/>
					<node selected="false" value="9"/>
					<node selected="false" value="10"/>
				</root>
			).node;
		]]>
	</mx:Script>
</mx:Application>


チェックボックスを表示するためのカスタムitemRendererクラス


package components
{
	import mx.binding.utils.BindingUtils;
	import mx.controls.CheckBox;
	import mx.controls.treeClasses.TreeItemRenderer;
	import mx.controls.treeClasses.TreeListData;
	
	public class Hoge extends TreeItemRenderer
	{
		[Bindable]
		public var checkBox:CheckBox;
		
		public function Hoge()
		{
			super();
		}
		
		override public function set data(value:Object):void {
			super.data = value;
		}
		
		override protected function createChildren():void{
			super.createChildren();
			
			checkBox = new CheckBox();
			checkBox.setStyle("verticalAlign","middle");
			BindingUtils.bindSetter(setSelected, checkBox, 'selected');
			this.addChild(checkBox);
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {     
			var treeListData:TreeListData = TreeListData(super.listData);
			
			super.updateDisplayList(unscaledWidth,unscaledHeight);
			
			if(super.data)
			{
				if (data.@selected.toString() == 'true')
				{
					checkBox.selected = true;
				}
				else
				{
					checkBox.selected = false;
				}
				
				checkBox.x = super.label.x;
				checkBox.y = ( unscaledHeight - checkBox.height ) /2;
				label.x = checkBox.x + checkBox.width + 20;
			}
		}
		
		private function setSelected(selected:Boolean):void
		{
			if (data)
			{
				data.@selected = selected.toString();
			}
		}
	}
}


7. drag and drop時の画像を変更したい

Q. drag and dropを独自に実装したときに、ドラッグする対象の画像を変更したいんだけど、どうするの??

A. DragManagerクラスのdoDragメソッドの第四引数に画像を指定してやればオッケーです。



DragManager.doDrag(dragInitiator, dragSource, event, img);


8. カーソルを変更したい

Q. 処理待ち中のカーソルを変更したりしたいんだけど、どうするの??

A. cursorManager変数の各種メソッドを使えば可能ですよー。

cursorManager.setBusyCursor()で、デフォルトの時計のアイコンを表示することができます。
cursorManager.removeBusyCursor()で、普通のアイコンに戻せます。

CursorManager.setCursor()を使うことで、独自のアイコンを指定することもできますよー。

9. ラッパーのhtmlのtitleをswfの中で設定したい

Q. htmlのタイトルを変更したいんだけど、どうするの??

A. ExternalInterfaceクラスを使いましょう。そうすることで、swfから、javascriptを実行することができます。



ExternalInterface.call("function(){if(location.href.indexOf('#',0) != -1){document.title = 'hogehoge'}}");


ラッパーhtmlの中でタイトルを最初から指定しておけばいいんじゃネーノ?って思うかもしれませんが、IEだけちゃんと動かないんですよ。なぜか'#'って表示されちゃうんですよね。

10. swfの置いてあるURLを取得したい

Q. swfの実行元のURLを取得して、swfの内部で使いたいんだけど、どうするの??

A. Application.application.urlで、実行されているswfのURLをフルで取得できるので、そこから正規表現で取得しましょう。



private function getHost():String
{
	var fullUrl:String = Application.application.url;
	var reg:RegExp = new RegExp("http://[^/]*/");
	if (reg.test(fullUrl)) {
		return reg.exec(fullUrl).toString();
	}
}


以上でーす。

結構偏った内容なんですが、お役にたてることが一つでもあれば幸いです。
ではではー。

AIRアプリ開発用Eclipseプラグイン「AIR GEAR」を使ってみました

こんにちは。
最近、バレーボールの応援にハマっている笹亀です。

最近、AIRを使って何かを作ってみたいなぁと思いました。
まずは、触れて見ようと思ってAptanaを使用してAIRを勉強しておりますが、今回は先日公開されたオープンソースAIRアプリケーション開発用EclipseプラグインAIR GEAR」を実際に導入して使ってみました。

そもそもきっかけは、「AIRで簡単にアプリを作ってみたい」と思いました。
いろいろ調べていると「Aptana」というアプリケーションを見つけました。さっそくインストールしてFLEXベースではなく簡単に作成できるHTMLベースでさくっとAIRアプリを作成してみました。

開発環境はEclipseベースで作成されているのでとってもEclipseっぽいです。


このようにいままでは、Aptanaを使って開発を行っていましたが、最近MacBookにパソコンを変更してからはEclipseで開発することになったこともあり、「AIR GEAR」の存在が気になり無性に試したくなりましたw

ということで、まずは準備を行いました。
AIR GEARをダウンロードして、ファイルをeclipse/pluginsフォルダ内に配置してEclipseを起動するだけで完了です。
次に、AIRアプリ開発を行うにはFlex SDKAIR SDKが必要になります。
両方ともAdobeのサイトからダウンロードできるので、入手しておきましょう。
FLEX SDKダウンロード
AIR SDKダウンロード

入手したSDKを解凍したら、適当な場所に保存しておきます。


Eclipseを起動して設定メニューに新しく追加された「AIR GEAR」に先ほどダウンロードしたSDKの場所を指定します。


AIR GEARプロジェクトを選択してプロジェクトを新規作成します。
作成後は、下記の図のようにコーディングを行うことはもちろん、実際に作成した内容の動作も確認できます。


AptanaAIR GEARの大きな特徴は、AptanaはHTMLベースでの開発にしか対応していません。AIR GEARを使うとFlexベースでの開発も行うことができ、Flexベースを選択すれば、Flashのアニメーションを使ったAIRアプリの開発も行うことができます。

これからAIRに挑戦する人や既にAIRを作成している人にとっても便利で有益なものだとおもいます。また、オープンソースで手軽にFlexのRADツールとしては使用できる点も大きいです。
私もこれからは「AIR GEAR」に乗り換えてAIR開発を行いたいと思います^^
皆さんもこの機会にぜひ「AIR GEAR」を使ってAIRアプリを作ってみてはいかがでしょうか。