massの日記

日々の薪

Androidマーケットの登録練習-アプリケーションの登録&公開&アップグレード-

前回までに作った公開用アプリをマーケットに並べる。
まずはhttp://market.android.com/publish/にログイン。
まだ1つもアプリを並べていないので、アプリケーションをアップロードをクリック。

まずはapkファイルをアップロードする。

特に問題なければ、アップロードが成功する。
ここで失敗する場合は、Manifestの設定がおかしいか、何かしらの設定ミスがある。
次はMarketで使われる画像の登録。最低限必要なものでいうと、スクリーンショット2枚と、アプリケーションアイコンの高解像度用の画像。

知らんがなーということで、スクリーンショットエミュレータからキャプチャとって作成。
イコン画像は最初の練習用なので、Androidのデフォルトアイコンをのまま拡大、あとでこちらは差し替えよう。
サイズはきっちり決まっていて、私はスクリーンショットは320*480のサイズを選んだ。
次は掲載情報と公開先の設定。言語デフォルトでは言語設定が英語になっているので、日本語のみに選択。

他言語圏で販売するなら最低英語のドキュメントは書かなくてはいけないと思う。

最後に同意するにチェックをいれ、公開、保存、削除のどれかを選ぶ。
公開を選択するとマーケットに公開される。
保存を押すと公開はされずに、登録したアプリケーションの情報が保存されるだけ。

バージョンアップをする場合は、Manifestのversion_nameとversion_codeをupして、再度apkファイルを作成。アップデートしたいアプリケ—ションの編集画面で、apkファイルを追加&差し替えする。
今日やってみた感想だと、アップデートの反映まで1時間はかかる模様。アップデートから30分後では反映されていなかったけど、2時間後には反映されていた。

Androidマーケットの登録練習-Developer登録&マーケット登録用アプリケーションの作成-

作ったアプリを公開するにして、AndroidのDeveloper登録が必要。
ここの登録作業ではDeveloperのヘルプにあるガイドラインに従って行った。
アカウントを作成するのに必要なものは、初期必要の$25と販売する場合はクレジットカード。
Appleと違い日本語化されているので、すんなり登録まで完了。
アカウントが作成できたら、今度はアプリケーションの登録。
公開するにあたり、Manifestにversion_nameとversion_code、そしてdebugの許可をfalseにする。以下、実際のファイルから追記した部分を抜粋。





上記のManifest記載が終了したらEclipseで作ったアプリケーションのPJを選択、右クリック

Export Singed Application...を選択、次に対象のPJを確認する画面が出てくる

Nextを押すと次はkeystoreの選択画面。
debug用のkeystoreしかない人は、ここで自分用のkeystoreを作成する。

Nextを押すと次はこのkeystoreのaliasの確認

Nextを押すと、最後にapkファイルの吐き出し場所を決める。

Finishを押して、公開用のアプリケーション作成は終了。

Androidマーケットの登録練習-まずはアプリを作ろう-(HtmlCodeHack)

先月から今月までで、いくつか野良アプリを作ってきた。
そろそろAndroidマーケットの公開方法も学んでおこうということで、
飲み会でネタをいただいたアプリを作成してみた。

・スマフォ用のページでどうやってHTMLが書かれているのかきになるけど、スマフォじゃ見えない
・最近UAだけじゃなくて、IPの帯域でキャリア判別しているところ増えた

つまりは、スマフォで表示しているWebページのHTMLが見える、
そんなアプリがあればいいねということ。

おそらくは色んな既存アプリが既に出ているのだろうけど、
今回はマーケットの登録までやってみよう!ということで制作に取りかかってみた。

今回のアプリバージョン1.5、できうる限りの下位バージョンを使ってみた。
作成したActivityは4つ。
まずは見たいWebページのURL入力画面であるMainActivity

次にWebページを表示するWebBrowserActivity

その次に表示しているWebページのHTMLソースを見るHtmlHackActivity

上記のHtmlHackActivityで読み取ったHTMLは編集可能なようにEditTextに入れておいた。
このEditTextを編集し、ローカルのHTMLファイルを表示するLocalBrowserActivity

すべての機能はMenuボタンに配置。
GoogleのLatitudeとかGmailとか見ていて、Androidはここに機能ボタン集結させておけば、説明するにしてもMenuボタンを押して、の一言で説明が事足りる。
画面上に置けるようなかっこいいのができるまでの暫定処置ともいう。

Code4LibJP TechCamp2日目-午後の部、Androidと戯れよう-

午前に作ったHerokuアプリ。
今度はこれの叩く側を作成する。

叩く側として今回作るのはAndroidアプリ。

以前作ったアプリをベースにして作成する。
このアプリで実装することを優先度順に並べてみた。

TwitterBotへのリクエスト成功(Android×Herokuでの連携)
図書館検索(市区町村指定orGPSによる検索)
書籍検索

途中までは作成していたけど、残り半日で動くものまで作るにして、
これらをすべて詰め込めるのかをもんもんと考えた。
結果として、外部API連携3つをすべてやりきるには、各APIとの連携テスト、本当にシンプルな使い方での通信成功が1時間以内にできなければ諦めようとの結論に至った。
すべてをやりきるのは無理でも、最低限できることを実装しようという形。

1、図書館検索 都道府県での検索はクリア
2、図書館検索 テストが非常に時間がかかるので一時保留
3、書籍検索 Amazonのsignature生成につまづき、一時保留
4、TwitterBotとの連携 クリア

1〜4を各自Modelレベルでテスト→実装を行い、1と4は1時間以内にクリア。
2と3に関しては、1時間以内にクリアできなかったので保留。

1と4でできること、それは。
任意の図書館で何をしたかBotに呟かせることで、図書館の利用目的、利用頻度の統計をHeroku上のアプリで統計的に出力する。

書籍系の機能は断念したけど、今回の足がかりとして、図書館利用者の交流タイムラインは実装できる。

AndroidでTDDをひたすら繰り返すこと、4時間。
なんとか叩くことだけはできるようになった。そして夕飯に。

夕飯後のタイムは翌日の成果発表、しかし、会社があるため、Heroku上に成果発表物をUPするページを作成。
アプリをββ版として公開するため、野良アプリの公開方法をチェック。


野良アプリの作り方
Eclipse>PJ選択、右クリック、Android Tools>Export Signed Application...を選択。
Keystoreを選択画面がでるので、自分のkeystoreを選択。
apkファイルの出力先をきかれるので、自分のローカルPCに保存。
保存したapkファイルをherokuプロジェクトのpublic以下に移動。
public以下に配置したファイルを落とさせるため、htmlに下記のAタグを記入。
a href="http://libdroidbot.heroku.com/BookInLibrary.apk"

BookInLibrary.apkは自分が作ったapkファイルの名前。public以下においてあるので、絶対パスで記入。

こんな感じで勢いで作ったHeroku×Android連携アプリ。
限られた時間で1パターンとはいえ、動きを作れたことが嬉しかった反面、
デザインなどもろもろいじれなかったことを反省。

自分の力不足、勉強不足を痛感しつつ、このTechCampに参加したことで得られたことは、昨年スタッフとして参加した東京Ruby会議、Ruby会議2010と同様、すごい貴重なものだった。

Code4LibJP TechCamp2日目-午前の部、Herokuと戯れよう-

3/5~3/7に開催されたCode4Lib JAPANのTechCampに参加した。
この団体の趣旨としては、日本の図書館システムをよりよくしよう、というもの。
メンバーは、図書館関係者、図書館情報学を履修している学生、企業に努めている方々、など様々。

ここでは、自分がCamp2日目に作ったものを晒す。
2日目は各々好きなものを作る日。
午前中にまずしたのは、何を作るかをまとめること。
当日に書いたメモは下記。


code4libjpcamp_20110306.txt
#Androidアプリ

#図書館を指定
#近くの図書館
#指定した市区町村の図書館

#本を検索
#標題
#著者
#出版社

#貸し出し状況の表示
#貸し出し中
#借りれます

#tweeter_bot
#借りました!
#借りたいです!
#返しました!

先日のブログでのせた図書館APIを利用して、〜図書館で本を借りる、返した、借りたい!というのを叫ぶ。
本を返した人にはコメントをつけてもらうTwitterBotとの連携アプリ。
Androidアプリでいまいる、図書館を指定、本を借りるor返すor借りたいのかを叫ぶ。
Twitterのつぶやきには図書館と本のHashTagをつけて、後からタイムライン上で追えるようにする。

Botにした理由。
自分が手がけているWebサービスで、Twitter,Facebookのアカウントを利用したサービスがあるが、実は結構自分のアカウントの利用は敷居が高いのではないかと推察。
アカウント名=本人とひもづいているものもあり、ソーシャルなものだからこそのリスクが伴う。
私個人としては、図書館で借りた本を晒されたところで、マニアックな人生が晒されるだけなので、今更社会的な損失はないに等しい。
逆に、相方には自分の借りた本を人にさらされるのは嫌!なにそれ怖い、みたいな反応をされた。

私がやりたいのは本の感想交換と図書館の活性化、となると、感想交換はISBNベースのHashTagがあれば、TwitterのTimeLineでことたりる。
感想を言い合うのなら、そこで自分のアカウントでやればよい。
アプリではその道を作る手助けになればよい。

最終的には1日である程度動くものを作らなくてはいけない。
以上のことをもんもんと考え、午前10時から開発に着手。

午前のタスク TwitterBotを作ろう!
なにで作るか?→Heroku!
まずすることは?→Herokuにアプリケーションを追加&Twitterアカウントの取得(libdroidbot)

今の会社に入社して1年と4ヶ月、周りの先輩に教えてもらい、自分も嬉しさを実感したTDDでの開発を決意。
ひたすらTDDを繰り返す。お昼に休憩いれ、13時半頃にBotができた。


$ heroku create libdroidbot
$#中略
$ git push heroku master
$ heroku db:migrate
$ # 最終的にspecを流した結果
$ bundle exec rspec spec/
$ Finished in 9.57 seconds
$ 30 examples, 0 failures, 7 pending

Botであると同時に、APIから取得できるLibraryIDを利用して、図書館の活動履歴を取得しているので、図書館毎の活動履歴を下記から参照できる。
http://libdroidbot.heroku.com/

最終的に簡単なListページを作成し、14時に終了。+2時間。
午前の部はここまで。

Android×TDD(model)

先日から取り組んでいたAndroidのTDD、modelのTestもかいてみた。
今回はActivityではないから、extendするTestClassは前回とは違う。
Contextの受け渡しはする予定だらAndroidTestCase。

それではまずは実装クラスから。
今回のmodelは図書館。市区町村名or緯度経度から図書館の一覧を取得する。
利用するAPIhttp://calil.jpから提供されているもの。

package jp.android.library.information.model;

//import 省略

public class LibraryUtil {
	private String libraryId = null;
	private String libraryName = null;
	private Double libraryLatitude = null;
	private Double libraryLongitude = null;
	private String libraryPlaceName1 = null;
	private String libraryPlaceName2 = null;
	
	public LibraryUtil(HashMap<String,String> hash) {
		setLibraryId(hash.get("systemid").toString());	
		setLibraryName(hash.get("systemname").toString());	
		setLibraryPlaceName1(hash.get("pref").toString());	
		setLibraryPlaceName2(hash.get("city").toString());
		String[] gecode = hash.get("geocode").split(",");
		setLibraryLatitude(Double.valueOf(gecode[1]));
		setLibraryLongitude(Double.valueOf(gecode[0]));
	}

	private void setLibraryId(String id) {
		libraryId =id;
	}

	private void setLibraryName(String name) {
		libraryName = name;
	}
	
	private void setLibraryPlaceName1(String place1) {
		libraryPlaceName1 = place1;
	}
	
	private void setLibraryPlaceName2(String place2) {
		libraryPlaceName2 = place2;
	}
	
	private void setLibraryLatitude(Double latitude) {
		libraryLatitude = latitude*1E6;
	}
	
	private void setLibraryLongitude(Double longitude) {
		libraryLongitude = longitude*1E6;
	}

	public String getLibraryId() {
		return libraryId;
	}
	
	public String getLibraryName() {
		return libraryName;
	}

	public String getLibraryPlaceName1() {
		return libraryPlaceName1;
	}

	public String getLibraryPlaceName2() {
		return libraryPlaceName2;
	}

	public Double getLibraryLatitude() {
		return libraryLatitude;
	}
	
	public Double getLibraryLongitude() {
		return libraryLongitude;
	}

	public static List<LibraryUtil> findLibraryByPlace(String place1, String place2) {                
            // 省略
        }
	
	public static List<LibraryUtil> nearbyLibraries(Double lat,Double lon) {
            // 省略
        }
	
	private static List<LibraryUtil> parseXml(XmlPullParser parser) throws XmlPullParserException, IOException {
            // 省略
        }
}


API利用部分は説明は割愛。
HTTPRequestを飛ばし、返されたXMLをparseして、LibraryUtilという図書館オブジェクトを作成する。
今回テストするのはHTTPの通信部分ではなく、図書館オブジェクトの生成部分。
意図したオブジェクトができているか確認するのがテストの目的。
前回のActivityとやっていることはほとんど同じ。あえてあげるなら、前回はassertの文法でNotNullというものしか使わなかったけど、今回は予測値と実態値が等しいか比較するassertEqualsを使ったこと。

package jp.android.library.information.test.model;

// import 省略

public class LibraryUtilTest extends AndroidTestCase {
	private LibraryUtil library = null;
	
	@Override
	protected void setUp() throws Exception {
    	LibraryUtil[] libraries = LibraryUtil.findLibraryByPlace(TestDefine.LIBRARY_PLACE1, TestDefine.LIBRARY_PLACE2);
    	library = libraries[0];
	}
	
	public void testGetLibraryId() throws Exception {
		assertEquals(TestDefine.LIBRARY_ID,library.getLibraryId());
	}
	
	public void testGetLibraryName() throws Exception {
		assertEquals(TestDefine.LIBRARY_NAME,library.getLibraryName());
	}

	public void testGetLibraryLatitude() throws Exception {
		assertEquals(TestDefine.LIBRARY_LATITUDE,library.getLibraryLatitude());
	}

	public void testGetLibraryLongitude() throws Exception {
		assertEquals(TestDefine.LIBRARY_LONGITUDE,library.getLibraryLongitude());
	}

	public void testGetLibraryPlaceName1() throws Exception {
		assertEquals(TestDefine.LIBRARY_PLACE1,library.getLibraryPlaceName1());
	}
	
	public void testGetLibraryPlaceName2() throws Exception {
		assertEquals(TestDefine.LIBRARY_PLACE2,library.getLibraryPlaceName2());
	}
}

まだ実行していないので、どこかにエラーがあるかもしれない。
ただ、テストがかけているから確認はさほど手間ではない。
モデルのテストが終われば、このモデルを呼び出す側ではモデルオブジェクトが間違っているといった心配はしなくてよい。
など、テストファーストでやった場合のメリットは後になるほど感じられると思う。
今回の開発サイクルは↓の形で進めた。

  1. アプリケーションプロジェクトで呼び出すクラスorメソッドを作成
  2. テストプロジェクトでテストクラスorテストメソッドを作成
  3. テスト実行
  4. NG
  5. 実装
  6. テスト実行
  7. OK

1でそのまま実装までしないよう踏みとどまるのが大事。

Android×TDD

昨年度からAndroidのアプリをチラホラ作り始めた。
一人でもくもく作っていて、何が一番つらかったかというと確認作業。
ちょっとしたリファクタリングでもエミュレータ起動して動きを確認しないといけない。
このコストは時間的にもそうだけど、精神的にもじわじわくる。
リファクタリングしたい→確認が面倒→一応動いているし、まあこのままでもいいか。
という流れに非常になりやすいと思う。
もしくは、リファクタリングした後で、1ステップずつではなくて、まとめて確認とか。

あくまで自分の個人的な見解だけれど、Androidアプリだと複数人でわいわい作るのではなく、一人でガリガリ作るから、こういった状況になりやすいと思う。
そこでテスト。テスト駆動開発。TestDrivenDevelopment。
RubyOnRailsで慣れ親しんだフロー、これをAndroidでもやっていきたい。
テストを書くor考える→テスト実行&失敗→実装→テスト実行&成功。

そんなわけで、まずは初めの1歩を踏んでみた。

今回はActivityのテストを書くことにしたので、Androidから提供されているJUnitのFramewark、TestSuiteを使用。
何故これを使ったかというとActivityのライフサイクル部分を吸収してくれるから。

下のがアプリケーションの実装コード。import文は長いので省略。

package jp.hoge.android.activity;

public class MainActivity extends Activity {
	private LinearLayout ll;
	private final int WC = ViewGroup.LayoutParams.WRAP_CONTENT;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);
    	this.setContentView(R.layout.main);
    	ll = (LinearLayout) findViewById(R.id.ll);
    	
        ImageView icon = new ImageView(this);
        icon.setImageDrawable(@drawable.icon);
        ll.addView(icon);
        TextView name = new TextView(this);
        name.setText("hoge");
        ll.addView(name);
        Button button = new Button(this);
        button.setText("Next");
        button.setOnClickListener(new OnClickListener() {
    		public void onClick(View v) {
    	            Intent intent = new Intent(MainActivity.this, NextActivity.class);
    	            startActivity(intent);
    		}
        });
        ll.addView(button);
}

Activityとしてはシンプルなもので、画面上にユーザアイコン、ユーザ名、ボタンを表示するだけ。
今回はこれのテストを書いてみた。

まずはテストプロジェクトの作成、Eclipseで開発しているとAndroidプロジェクトでTest用のプロジェクトがある。
今回はこちらからプロジェクトを作成。
File>New>Project>Android>Android Test Project
作成する際にテスト対象をきかれるので、テストしたいアプリケーションプロジェクトを指定。
AndroidManifest.xmlには下記のような記述。

    <instrumentation android:targetPackage="jp.hoge.android"
    				 android:name="android.test.InstrumentationTestRunner"
    				 android:label="Test for Hoge Application" />

で、肝心のテストコードは下記。import文は省略

package jp.hoge.android.test.activity;

public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
	private LinearLayout ll;
	
	public MainActivityTest() {
		super("jp.hoge.android", MainActivity.class);
	}
	
	@Override
	protected void setUp() throws Exception {
		super.setUp();
		ll = (LinearLayout) getActivity().findViewById(R.id.ll);
	}
	
	public void testShowLoginUserIcon() throws Exception {
		ImageView userIcon = (ImageView) ll.getChildAt(0);
		assertNotNull(userIcon);
	}

	public void testShowLoginUserMessage() throws Exception {
		TextView userName = (TextView) ll.getChildAt(1);
		assertNotNull(userName);
	}

	public void testShowLoginUserButton() throws Exception {
		Button button = (Button) ll.getChildAt(2);
		assertNotNull(button);
	}
}

Javaで生成した子のView要素はgetChildAtで取得。表示要素が正しく表示されているか確認する。
後はテストを走らせて、Eclipse上にJUnitのテストステータスバーが表示され、green一色になればOK。
とりあえず、勢いでここまでやってみた。次はactivityではなくmodelのテストに取り組む予定。