AIR for Android + Google App Engine で簡単Androidアプリ開発

Androidに関しては今後勉強して行きたいと思っている超初心者です。一応念の為。


11/8にAndroidの会に初参加してきました。
日本Androidの会11月の定例イベント
http://android.siprop.org/index.php?%CA%D9%B6%AF%B2%F1%2F2010%C7%AF11%B7%EE%A4%CE%A5%A4%A5%D9%A5%F3%A5%C8


Androidの勉強って言うか、端末のタッチ&トライ目的で行ったのですが、
AIRで作るAndroidアプリの講演を聞いて、
S3BlazeDSのコミッタとしてAIR for Android + Google App Engineのサンプルぐらい公開しておかないとイケない気がしたので作ってみました。

作ったもの

ツイッターっぽい何か。
エミュレータの画面です。

このイメージみたらなんとなくわかると思いますが、そういうものです。
Google App Engineを使ってるので自分でサーバーを準備したり、レンタルサーバーの契約したり等は必要ありません。


こんな簡単なデモですが、作成の流れを紹介します。
(かなりテキトーですが雰囲気はつかめるんじゃないかと)


その前に、

S3BlazeDSとは?

S3BlazeDSを使えば、Flex/AIRアプリケーションからGoogle App Engine上のJavaオブジェクトのメソッドを簡単に呼び出す事が出来ます。
(もっとわかりやすいちゃんとした説明→ http://www.moongift.jp/2010/08/s3blazeds/)
http://code.google.com/p/s3blazeds/

1.AIR for Android の開発環境準備します。

http://labs.adobe.com/technologies/flashbuilder_burrito/
ここからAdobe Flash Builder "Burrito"をダウンロードして、インストールすれば完了です。

2.AIRAndroidアプリを作成します。

インストールしたFlash Builderを使ってつくっていきます。

ファイル > 新規 > Flex モバイルプロジェクト を選択します。

プロジェクト名をテキトーに入力して次へ進みます。

そのまま次へ進みます

サーバーの設定をする画面ですが、とりあえずここでは何もしないで次へ進みます。

ここも特に何もする必要ないので終了ボタンを押下します。

こんな感じでプロジェクトが作成されます。

viewsパッケージにあるmxmlファイルを開いて画面を作ります。

エディタの上の方にある「ソース|デザイン」のボタンを押してデザインに切り替えるとドラッグアンドドロップでボタンなどを配置して画面を作る事ができます。
画面左下のコンポーネントタブの部品をドラッグアンドドロップで配置します。
画面右のプロパティタブで表示する内容や色等を変更できます。

こんな感じで配置してみました。

エディタの上の方にある「ソース|デザイン」のボタンでソースに切り替えます。

だいたいこんな感じのソースが表示されると思います。

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
		xmlns:s="library://ns.adobe.com/flex/spark" title="ツイッターみたいなの">

	<fx:Script>
		<![CDATA[
			protected function button1_clickHandler(event:MouseEvent):void
			{
				// TODO Auto-generated method stub
			}
		]]>
	</fx:Script>

	<fx:Declarations>
		<!-- 非ビジュアルエレメント (サービス、値オブジェクトなど) をここに配置 -->
	</fx:Declarations>	
	<s:TextInput id="content" x="20" y="10"/>
	<s:Button x="20" y="73" label="つぶやく" click="button1_clickHandler(event)"/>
	<s:List id="tweetList" x="10" y="165" width="440" height="494"></s:List>
</s:View>
これを変更して、つぶやいたらリストに追加されるようにしてみます。

こんな感じでしょうか。

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
		xmlns:s="library://ns.adobe.com/flex/spark" title="ツイッターみたいなの">

	<fx:Script>
		<![CDATA[
			//ボタンを押した時の処理
			protected function button1_clickHandler(event:MouseEvent):void
			{
				//つぶやきをリストの先頭に追加する。
				tweetListData.addItemAt(this.content.text, 0);
			}
		]]>
	</fx:Script>

	<fx:Declarations>
		<!-- 非ビジュアルエレメント (サービス、値オブジェクトなど) をここに配置 -->
		
		<!-- つぶやきデータを保存するリスト-->
		<s:ArrayCollection id="tweetListData">
		</s:ArrayCollection>
	</fx:Declarations>	
	
	<s:TextInput id="content" x="20" y="10"/>

	<!-- ボタンをおしたらbutton1_clickHandlerメソッドを呼び出すようにクリックイベントを設定します -->
	<s:Button x="20" y="73" label="つぶやく" click="button1_clickHandler(event)"/>
	
	<!-- dataProviderにつぶやきデータのArrayCollectionをバインディング -->
	<s:List id="tweetList" x="10" y="165" width="440" height="494" dataProvider="{tweetListData}"></s:List>
</s:View>
とりあえずこれで、ツイッターっぽい?何かが出来ました。

まだ、これだとアプリを終了したらつぶやきが消えてしまうので、
S3BlazeDSを使ってGoogle App Engineにつぶやきを保存するようにしてみます。

3.Google App Engine側の作成

そろそろ面倒くさくなってきたので、(おい…)
サーバー側はSlim3(Google App Engine用のフレームワーク)のスタートガイドのプログラムをそのまま使うことにしました。


説明どおりに進めていけばツイッターっぽいWebアプリが簡単に作れるので、こちらのページを参考に作ってみてください。
http://sites.google.com/site/slim3appengine/getting-started
日本語ページもあります。
http://sites.google.com/site/slim3documentja/getting-started


もし何か分からない事があれば、 #appengine とか、#slim3 とかのハッシュタグをつけてツイッターで質問すれば誰か答えてくれるかもしれません。

4. Google App Engine側のS3BlazeDSの設定

Google App EngineAndroidを連携させます。
まず、Google App Engine側から。

作成するファイル

war/WEB-INF/remote-config.xml
war/WEB-INF/service-config.xml

追加するjar(http://code.google.com/p/s3blazeds/からダウンロードできます)

war/WEB-INF/lib/flex-messaging-common.jar
war/WEB-INF/lib/flex-messaging-core.jar
war/WEB-INF/lib/flex-messaging-remoting.jar
war/WEB-INF/lib/s3blazeds.jar

修正するファイル

war/WEB-INF/web.xml
war/WEB-INF/appengine-web.xml

remoting-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service" 
    class="flex.messaging.services.RemotingService">

    <adapters>
        <adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>
    </adapters>

    <default-channels>
        <channel ref="my-amf"/>
    </default-channels>
    
    <!-- AIRから呼び出したいGoogleAppEngineのJavaオブジェクトをここで定義してます -->
    <destination id="TwitterService">
    	<properties>
    		<source>tutorial.service.TwitterService</source>
    		<scope>request</scope>
    	</properties>
    </destination>
    
</service>
service-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
    <services>
        <service-include file-path="remoting-config.xml" />
        <service class="org.slim3.blazeds.bootstrap.SerializerBootstrapService" id="s3blazedsbootstrap"/>
    </services>

    <channels>
        <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
        </channel-definition>
    </channels>

    <logging>
        <target class="flex.messaging.log.ConsoleTarget" level="Error">
            <properties>
                <prefix>[BlazeDS] </prefix>
                <includeDate>false</includeDate>
                <includeTime>false</includeTime>
                <includeLevel>false</includeLevel>
                <includeCategory>false</includeCategory>
            </properties>
            <filters>
                <pattern>Endpoint.*</pattern>
                <pattern>Service.*</pattern>
                <pattern>Configuration</pattern>
            </filters>
        </target>
    </logging>

    <system>
        <redeploy>
            <enabled>false</enabled>
        </redeploy>
        <manageable>false</manageable>
    </system>
</services-config>
web.xmlに↓の内容を追記してください
    <!-- Http Flex Session attribute and binding listener support -->
    <listener>
        <listener-class>flex.messaging.HttpFlexSession</listener-class>
    </listener>

    <!-- MessageBroker Servlet -->
    <servlet>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <display-name>MessageBrokerServlet</display-name>
        <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
        <init-param>
            <param-name>services.configuration.file</param-name>
            <param-value>/WEB-INF/flex/services-config.xml</param-value>
       </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>
appengine-web.xmlを変更

S3BlazeDSを動かす為にはSessionを有効にする必要があります。
あと、現時点ではまだS3BlazeDSはSlim3のHotReloadingに対応していない為、HotReloadingを無効にします。
↓を参考に修正してください。

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
	<application></application>
	<version>1</version>
	
	<precompilation-enabled>true</precompilation-enabled>
	
	<system-properties>

	    <!-- Slim3のHotReloading機能をオフにします。 -->
	    <property name="slim3.hotReloading" value="false"/>

	    <property name="java.util.logging.config.file" value="WEB-INF/classes/logging.properties"/>
	</system-properties>

	<!-- Sessionを有効にします -->
	<sessions-enabled>true</sessions-enabled>

</appengine-web-app>

5. 次にAIR側のS3BlazeDSとの連携

こんな感じに変更します。

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
		xmlns:s="library://ns.adobe.com/flex/spark" title="ツイッターみたいなの"
		creationComplete="getTweet()">

	<fx:Script>
		<![CDATA[
			import mx.effects.Tween;
			import mx.rpc.AsyncResponder;
			import mx.rpc.AsyncToken;
			import mx.rpc.events.FaultEvent;
			import mx.rpc.events.ResultEvent;
			import mx.rpc.remoting.mxml.RemoteObject;
			
			protected function button1_clickHandler(event:MouseEvent):void
			{	
				//つぶやきをサーバーに送信する。
				var token:AsyncToken = 	TwitterService.tweet(
						{'content':content.text}
					);
				token.addResponder(
					new AsyncResponder(
						function(re:ResultEvent, obj:Object=null):void{
							//成功した時の処理
							getTweet();
						},
						function(ee:FaultEvent, obj:Object=null):void{
							//失敗した時の処理
							trace(ee);
						}
					)
				);
		
			}
			private function getTweet():void{
				//つぶやき一覧をサーバーから取得する。
				TwitterService.getTweetList();
			}
		]]>
	</fx:Script>

	<fx:Declarations>
		<!-- 非ビジュアルエレメント (サービス、値オブジェクトなど) をここに配置 -->
		
		<!-- サーバーと通信するリモートオブジェクト -->
		<s:RemoteObject id="TwitterService" 
						destination="TwitterService"
						endpoint="http://localhost:8888/messagebroker/amf">
		</s:RemoteObject>
		
	</fx:Declarations>	
	
	<s:TextInput id="content" x="20" y="10"/>
	<s:Button x="20" y="73" label="つぶやく" click="button1_clickHandler(event)"/>
	
	<s:List id="tweetList" x="10" y="165" width="440" height="494" 
			labelField="content"
			dataProvider="{TwitterService.getTweetList.lastResult}"></s:List>
</s:View>

という事で完成です。

つぶやきがGoogle App Engineに保存されるようになったと思います。


全体的に中途半端な説明で一体どういう人をターゲットにした記事なのかよくわからなくなりましたが、なんとなくAIR for Andoroid on Google App Engineの雰囲気はつかめて頂けたんじゃないかと言う事にしておきます。


Google App Engineはプログラム書くだけでOK、無料で始められてAIR for Andoroidのサーバー環境としても魅力的だと思います。

もし、AIR/Flexな人でサーバーサイドのJavaは苦手だなーって思った人は

jsonengineがお勧めです。
http://code.google.com/p/jsonengine/
JSONでの連携になりますが、サーバーサイドのコーディング不要でGoogle App Engineを使う事ができます。
詳しくはこちら。
http://jxck.bitbucket.org/jsonengine-doc-ja/build/html/summary.html

あと、AndroidAIR/Flexな人で、Google App Engineに興味もった人は、

appengine ja nightというGoogle App Engine勉強会がお勧めです。
http://atnd.org/events/9571
キャンセルも結構あるので補欠でも登録しておくと良いかもです。