俺のコントローラのprotectedがpublicなわけがない

こんにちは。
最近、東北TECH道場(仙台道場)でAndroidの講師してます、GeNERACE CTOけんたろです。
今回は東北TECH道場で行なっている活動やハックについて書こうと思いましたが、弊社の仕事でCakePHP(v2.3.1)を使っていて気になったことについてメモします。

Continue reading

Ubuntuのススメ ver 2013/04

20090433-11

こんにちは、GeNERACE CTO けんたろです。

僕のメインの開発環境のOSはUbuntu 12.10です。
Ubuntuをメインの開発環境にしてから約2年。
今回はUbuntu 12.10で僕がよく使っている便利なソフトやツールについて書こうと思います。

Continue reading

githubとAndroidとJenkinsの素敵な関係

head
こんにちは、GeNERACE CTO村松です。

GeNERACEではAndroidアプリ開発の継続的インテグレーションと企画側とのシームレスな連携の為にJenkinsを導入しています。
今回はその導入についてまとめます。
前提条件はJenkinsを導入するサーバに

  • Java 1.6がインストールされていること(Androidのビルドの関係で1.7はおすすめしない)
  • apacheがインストールされて起動していること
  • gitがインストールされていること
  • antがインストールされていること
  • androidのkeystoreが作成済みでリポジトリにコミットされていること

とします。

AndroidSDKを導入する

まず、Jenkinsを導入するサーバ上にlinux用のAndroidSDKを導入します。

$ sudo cd /var/lib/
$ sudo wget http://dl.google.com/android/android-sdk_r13-linux_x86.tgz #SDK取得
$ sudo tar zxvf android-sdk_r13-linux_x86.tgz
$ sudo mv android-sdk_r13-linux_x86 android-sdk-linux
$ sudo export PATH=$PATH:/var/lib/android-sdk-linux/tools/
$ sudo android update sdk -u #sdkアップデート

これでSDKの導入は完了。

Jenkinsを導入する

$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
$ sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
$ sudo yum install jenkins
#jenkinsがアクセスするディレクトリにアクセス権を割り振る
$ sudo chown -Rf jenkins /var/lib/jenkins/
$ sudo chgrp -Rf jenkins /var/lib/jenkins/
$ sudo chown -Rf jenkins /var/lib/android-sdk-linux
$ sudo chgrp -Rf jenkins /var/lib/android-sdk-linux
$ sudo service jenkins start #jenkins起動

通常はユーザー周りの設定を行ったり、セキュリティ周りの設定を行うのですが、今回は省略。

JenkinsにJenkins GIT pluginを入れる

Jenkinsを起動したら http://jenkins_hostname:8080/ にアクセス。
Jenkinsの管理>プラグインの管理>利用可能から”Jenkins GIT plugin”をインストールします。
これは、Jenkinsにデフォルトでインストールされている、”Git Client Plugin”とは別のgithubと連携する為のpluginです。

githubのリポジトリにhookの設定を行う

先ほどのJenkins GIT pluginとの連携設定をgithub上で行います。
これは、githubのリポジトリとjenkinsのジョブを繋ぐ為の設定です。
https://github.com/account_name/repository_name/settings/hooks/にアクセス。
Jenkins (Git plugin)という項目があるのでクリックし、Jenkins Urlという入力項目に以下のURLを入力します。

http://jenkins_hostname:8080/git/notifyCommit?url=git@github.com:account_name/repository_name.git

Activeにチェックを入れ、Update settingsをクリック。
以上でgithubのリポジトリとjenkinsのプロジェクトを繋ぐ設定がされます。
これで、このリポジトリに対してのプッシュやマージがあった場合、設定したURLをgithub側からキックしてくれます。

Jenkinsにプロジェクトの設定を行う

http://jenkins_hostname:8080/ にアクセス。
画像を参考にJenkinsにジョブを追加します。
Selection_003

  1. 新規ジョブ作成をクリック
  2. フリースタイル・プロジェクトのビルドを選択
  3. ジョブ名を入力
  4. OKをクリック。

画像を参考にJenkinsのジョブ設定を行います。
Selection_007

  1. ソースコード管理システム>>Git>>Repository URLに先ほどhookの設定を行ったリポジトリを入力。Branches to build>>Brannch Specifierにブランチ名を入力
  2. ビルドトリガ>>SCMをポーリングにチェック
  3. ビルド>>シェルの実行>>シェルスクリプトにビルド時に実行するshellコマンドを入力
  4. ビルド後の処理>>Email通知>>宛先に開発全体に飛ぶメールなどを設定。不安定ビルドも逐一メールを送信、ビルドを壊した個人にも別途メールを送信にチェックを入れ、保存をクリックします

項目1のリポジトリがprivateリポジトリの場合、あらかじめ以下ディレクトリにgithub認証用の鍵を置いておきます。

/var/lib/jenkins/.ssh

項目3のshellコマンドですが、GeNERACEでは以下のように設定しています。

export PATH=$PATH:/usr/apache-ant-1.8.3/bin #antのパス追加
#Android関連のパスを追加
export PATH=$PATH:/var/lib/android-sdk-linux/tools
export ANDROID_HOME=/var/lib/android-sdk-linux
export PATH=$PATH:/var/lib/android-sdk-linux/platforms
export PATH=$PATH:/var/lib/android-sdk-linux/platform-tools/
#androidアプリのプロジェクト初期設定
android update project -p /var/lib/jenkins/jobs/jenkins_job_name/workspace/
#jenkinsがgithubからcloneしたディレクトリに移動
cd /var/lib/jenkins/jobs/jenkins_job_name/workspace/
#ビルド用のantスクリプトを叩く(詳細は"アプリをAntでビルド出来るようにする"に記述)
/bin/sh build.sh
#成果物をWeb上から落とせる場所にコピーする
cp -rf ./bin/appname.apk /www/jenkins/appname.apk

アプリをAntでビルド出来るようにする

JenkinsからAntを実行しアプリをビルドする為のシェルスクリプトを追加します。

$cd /var/lib/jenkins/jobs/jenkins_job_name/workspace/
$vi build.sh #viエディタ起動、以下の内容を入力し保存する
-----ここから-----
#!/bin/sh

#リリース用ビルドを作成する
echo "build for distribution"
ant clean
ant release

cp ./bin/AppNameActivity-release-unsigned.apk ./bin/app_name.apk

#アプリのデジタル署名を行う
echo "sign apk"
jarsigner -J-Dfile.encoding=UTF-8 -verbose -keystore ./app_name.keystore -storepass keystore_password ./bin/app_name.apk keystore_area

#アプリのデジタル署名の確認を行う
echo "verify apk"
jarsigner -J-Dfile.encoding=UTF-8 -verify -verbose ./bin/app_name.apk

#パッケージの最適化
echo "zipalign apk"
zipalign -f -v 4 ./bin/app_name.apk ./bin/appname.apk

#パッケージの最適化の確認
zipalign -c -v 4 appname.apk
-----ここまで-----
#ビルドしてみる
$sh build.sh

ビルド完了後workspace/bin以下にappname.apkが出来ていることを確認します。

動作確認

設定したリポジトリ git@github.com:account_name/repository_name.gitにpushし、http://jenkins_hostname:8080/ にアクセス。
Jenkins上でビルドが実行されることを確認します。

ビルド結果確認

Jenkins上でビルド完了後、http://jenkins_hostname/appname.apk にAndroid端末でアクセス。
Android端末にダウンロードし、インストールを行い起動出来ることを確認します。

便利ツール導入

こちらのページで紹介されているJenkins Notifier for Chromeがビルド状態が分かり非常に便利なので導入します。
この時、企画側のChromeにもインストールしておくと更に良いです。

最後に

GeNERACEではこの仕組みを導入しているので、

  1. 企画側の改善提案を開発側が受ける
  2. 開発側が開発しリポジトリにpushする
  3. 企画側がjenkinsから落とし動作確認する

という流れで非常に良い連携が出来ています。
因みに、弊社アプリ宇宙上司をJenkinsでビルドした場合、EC2のt1.microだと14分、m1.smallで3分程度でした。
宇宙上司にはライブラリとしてAndEngine,AndEnginePhysicsBox2DExtension,FluctSDK,libGoogleAnalyticsV2を導入している為14分も掛かっていますが、普通のアプリであれば、恐らくt1.microで十分だと思います。
本当はAntからJUnitで行う単体テストの部分も書きたいのですが、また次の機会に書こうと思います。

ご覧いただきありがとうございました。

AndEngineでAndroidネイティブのView操作をSceneから行う

こんにちは
Zynga Japanを12月に退職し、GeNERACEという作りたての会社でCTOやってます、村松です。
GeNERACEではAndroidのネイティブゲーム開発にAndEngine(gituhub)を使ってます。

AndEngineはとっても便利ですが、ネイティブのViewと連携させるとより便利です。
今開発中のゲームもネイティブのViewをいくつかのSceneで使っています。
その際にScene1ではいらないけど、Scene2では使いたいとかいう場合ありますよね。
これ、単純にActivityのインスタンスを取得し、対象のViewにsetVisibilityで制御出来るようで実は出来ない。

何故か。

Viewはシングルスレッドモデルです。
AndEngineのSceneはActivityとは別スレッド。
SceneでネイティブのView操作を行うとアプリが強制終了します。

その為、こんな感じに実装してみました。

  • StageScene.java(ゲーム画面のクラス)
  • public class StageScene extends GeneraceAndEngineBaseScene implements ButtonSprite.OnClickListener, IOnSceneTouchListener, IOnAreaTouchListener{
    	private void showResult() {
    		// ネイティブのViewを表示状態にしたいYO!
    		getBaseActivity().visibleNativeViewFromId(R.id.edit_text_result);
    	}
    }
    
  • GeneraceAndEngineBaseScene.java(ゲーム画面の親クラス)
  • public abstract class GeneraceAndEngineBaseScene extends Scene implements ButtonSprite.OnClickListener{
    	private GeneraceAndEngineBaseActivity baseActivity;
    	public GeneraceAndEngineBaseActivity getBaseActivity() {
    		return this.baseActivity;
    	}
    }
    
  • GeneraceAndEngineBaseActivity.java(アクティビティ制御クラス)
  • public abstract class GeneraceAndEngineBaseActivity extends SimpleLayoutGameActivity {
    	Handler goneNativeViewHandler = new Handler();
    	Handler visibleNativeViewHandler = new Handler();
    	Handler invisibleNativeViewHandler = new Handler();
    	public void goneNativeViewFromId(final int id) {
    		new Thread(new Runnable() {
    			public void run() {
    				goneNativeViewHandler.post(new Runnable() {
    					public void run() {
    						findViewById(id).setVisibility(View.GONE);
    					}
    				});
    			}
    		}).start();
    		
    	}
    	
    	public void invisibleNativeViewFromId(final int id) {
    		new Thread(new Runnable() {
    			public void run() {
    				invisibleNativeViewHandler.post(new Runnable() {
    					public void run() {
    						findViewById(id).setVisibility(View.INVISIBLE);
    					}
    				});
    			}
    		}).start();
    		
    	}
    	
    	public void visibleNativeViewFromId(final int id) {
    		new Thread(new Runnable() {
    			public void run() {
    				visibleNativeViewHandler.post(new Runnable() {
    					public void run() {
    						findViewById(id).setVisibility(View.VISIBLE);
    					}
    				});
    			}
    		}).start();
    	}
    }
    
  • activity_main.xml
  • <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    	xmlns:tools="http://schemas.android.com/tools"
    	android:layout_width="match_parent"
    	android:layout_height="match_parent" >
    
    	<org.andengine.opengl.view.RenderSurfaceView
    		android:id="@+id/renderview"
    		android:layout_width="fill_parent"
    		android:layout_height="fill_parent" />
    	<EditText
    		android:id="@+id/edit_text_result"
    		android:gravity="left|top"
    		android:inputType="textMultiLine"
    		android:layout_marginLeft="10dip"
    		android:layout_marginRight="10dip"
    		android:layout_marginTop="300dip"
    		android:visibility="gone"
    		android:layout_width="match_parent"
    		android:layout_height="100dip"/>
    </RelativeLayout>
    

    非同期処理とかで使う実装に似た感じ。
    なんかイマイチ綺麗じゃないなー、俺Handlerあんま好きじゃないんだよなーとか思うけど、もう今日は眠いのでこれで限界。(3:30 AMなう)
    より良い実装が浮かんだら書き換えよう。そうしよう。

    そういえば、AndEngineってZyngaのNicolas Gramlich(facebook)さんが作ってるですよね。
    Zynga Japan辞めてもなんやかんやでZyngaにお世話になることはまだまだありそうです。