kazz187.log

技術ネタとか

Android アプリ開発未経験者が Animetick クライアントを作るまで

Animetick for Android をリリースしました

9月の頭にリリースしました、アニメ視聴管理サービス Animetick ですが、この度、 Android 向けクライアントアプリを無事リリースすることができました。

f:id:kazz187:20131107200458p:plain

Animetick - Google Play の Android アプリ

スマートフォン対応に至る経緯

「アニメ見るときに毎回 PC で視聴管理するなんて意識の高いことは辛い」

「寝っ転がって適当にスマホで視聴管理したい」

という怠惰な欲求から Animetick スマートフォン対応プロジェクトはスタート。

友達の iOS エンジニア(id:yayugu)が、 Animetick キテる、 iOS アプリ作ろう!とのことで、 iOS アプリを作ってくれることに。

じゃあ私は Android 版作るよー!ってことで、ノリで Android 開発を始めることに相なりました。

以下、開発者モード。

Web か Native か

チケット管理がメインとなるアプリということで、チケット画面におけるスクロールの快適さが一番重要と捉え、ネイティブで行くことに。

(というか最近スクリプト言語ばっかりな生活なので Java 書きたい気持ちが圧勝)

開発環境選び

漢なら黙って (Emacs|Vim) とかそろそろ辞めたい。

候補に上がったのは以下の2つ。

ゲームとか、ガチネイティブ開発するわけじゃなく、簡単な ListView を操作する系のアプリなので、新し目の Google 謹製 Android Studio にチャレンジしてみることに。

画面はこんな感じ。

f:id:kazz187:20131107201519p:plain

Android Studio最速入門~効率的にコーディングするための使い方

Android Studio 入門に見せかけた IntelliJ 入門記事。丁寧。

ハマリポイント Gradle

Android Studio は Gradle でビルド周りを管理する。が、そのわりに Gradle サポートが薄い。

GUI でポチポチできるレベルではないし、そのまま生で書いても補完系のサポートが無い。

Android Studio は頻繁にバージョンアップがあるが、カジュアルにバージョンを上げるとビルドが通らなくなったりする。本気で謎のエラーに悩まされる。でも上げる。

その時は、新規プロジェクトを作り、旧プロジェクトの .git 以下を持ってきて、必要なソースファイルを checkout し、設定ファイルは git diff でどこが変わったか確認するほうが解決まで早かった。こうして今日もバッドノウハウが溜まっていく。

最終的にこんな Gradle 設定ファイルでビルドしている。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.6.+'
        classpath group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.2.3'
        classpath group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.2.3'
        classpath 'com.github.chrisbanes.actionbarpulltorefresh:library:0.7.+'
    }
}
apply plugin: 'android'

repositories {
    mavenCentral()
}

android {
    compileSdkVersion 18
    buildToolsVersion "17.0.0"

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 18
    }
}

dependencies {
    compile 'com.android.support:appcompat-v7:+'
    compile 'com.fasterxml.jackson.core:jackson-core:2.2.2'
    compile 'com.fasterxml.jackson.core:jackson-databind:2.2.2'
    compile 'com.github.chrisbanes.actionbarpulltorefresh:library:0.7.+'
}

tasks.withType(Compile) {
    options.encoding = 'UTF-8'
}

Maven や Github などで管理されているライブラリに対して依存関係を指定出来て便利。

エミュレータか実機か

エミュレータ遅すぎるので USB で実機接続して開発。

最近買った Xperia UL がさくさくで捗る。

エミュレーターこういうのもあるみたいなので時間があるときに試してみたい。

実装編

認証

まずはログイン周りから着手した。

認証は WebView で Twitter の認証ページを使っている。(よくわからない Native 画面に Twitter の ID, Password を入れたくない。)

追記: セキュリティ周りはよく突っ込まれるので補足すると、これはベストな実装というわけではなく、妥協案です。 (2013/11/08)

ログイン後は session_id を WebView 側の JavaScript 経由で Native 側の Java に bridge する。

WebView

JavaScript 側はこんな関数を作っておく

animetick.app.getSessionForNativeApp = function() {
    return document.getElementById('animetick_session').getAttribute('data-animetick-session');
};

JavascriptInterface を使って Java のオブジェクトを JavaScript 側から呼び出せるように対応付ける。

webView.addJavascriptInterface(new JsObject(), "animetickObj");

Java 側のオブジェクトへの JavascriptInterface の指定はこんな感じ

class JsObject {
    @JavascriptInterface
    public void saveSessionId(String sessionId) {
        authentication.saveSessionId(sessionId);
    }
}

Android 4.2 からは "@JavascriptInterface" Annotation をつけないといけないので注意

こういう感じで JavaScript 内部で Java のオブジェクトとその メソッドを呼び出すことができる。

view.loadUrl("javascript:animetickObj.saveSessionId(animetick.app.getSessionForNativeApp())");

これで認証周りは終了。

黒魔術はここまで。

JSON の取得・パース

Android 標準の JSON ライブラリは、 InputStream -> String の変換をしないとパースできないみたいなので微妙。

悩んだ挙句 Jackson というライブラリを使ってみることに。

本格派エンジニアの工具箱 » 第27回 JSONデータを扱うためのJavaライブラリ「Jackson Java JSON-processor」

もちろん Gradle を使って Maven で入れる。(上記設定ファイル参照)

 ObjectMapper mapper = new ObjectMapper(jsonFactory);
 JsonNode rootNode = mapper.readTree(is);

このように InputStream から気軽に Tree に起こすことができた。あとは has や get で Tree node から適当な Model object へ と起こしてやればよい。

ListView

Animetick のチケットを JSON でサーバーから取ってきて ListView で整形して表示するだけの簡単なお仕事。

Layout 作成

Android Studio では カスタムビュー、レイアウトを GUI で簡単に作ることができた。

用意するのは2つ。

  • 外側のチケットを格納する ListView を書いた xml

f:id:kazz187:20131107194225p:plain

  • 内側の RelativeLayout でチケットのカスタムビューを書いた xml

f:id:kazz187:20131107194239p:plain

Android では ListView の中に更にカスタムビューを入れて・・・という入れ子構造を扱うことができる。各アイテムの高さも勝手に合わせてくれる。(いろいろ試行錯誤したが) 便利。

RelativeLayout が思いの外便利で、各 Text や Image の細かな View 配置ができるので、チケットのカスタムビューを作るのに役だった。

Adapter で Ticket model を ListView へ表示

Android では ArrayAdapter というものを用いて Model から ListView への表示を行うことができる。

ListView は List item を作成しておき、輪環状に使いまわすことで高速な描画を行っている。

f:id:kazz187:20131107200118p:plain

ListView はスクロールされると、 ArrayAdapter に対してこの convertView に position 番目のデータを map して渡してくれと

View getView(int position, View convertView, ViewGroup parent)

を呼び出し、 Model の情報を付加された View を取得し、描画する。

PullToRefresh

Twitter クライアントとかで下にびよーんって引っ張ったら更新が走るアレ

最初は Android-PullToRefresh を使っていたが、 Android の Module として扱わないと動作しない形式のライブラリであったり、動作がもっさりしてて辛かったのでキャンセル。

最終的に ActionBar-PullToRefresh に落ち着く。 AndroidGmail スタイル。

これは Gradle でサクッと入る。参照先は Github。便利。

参考になったのは

Effective Android

コミケで人気爆発で買えなかったので、達人で電子書籍版をポチった。

UI

結構悩んだのが UI。

チケットを表示して、タップするだけでは誤動作しそう。

でもスワイプや長押ししないと Watch できないのは直感的じゃなくて嫌。

なので、 Watch ボタンを常に表示し、サブメニューが開くようにしてみた。

f:id:kazz187:20131107201136p:plain

f:id:kazz187:20131107201147p:plain

ButtonView だと、デザイン的にダサいので、今回は TextView や ImageView をボタンの代わりに使ってみた。

Flat (笑)っぽい UI の完成。

それらの View をタップするとじわっと色が変わったり、メニューがさっと開いたり、無駄にアニメーションをつけたりしてみた。

今後

Web でできる機能をまだまだ実装しきれてないのでそれらを実装していく。

放送時間前に通知してくれる機能とか付けたい。

Web 側も、まだまだ面白くできそう。

ソーシャル感出したい。アニメグラフでつながる感覚。

Android 開発たのしい ✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌

Web サービスとそのクライアントアプリ作成のいい勉強になった。

たくさんの新しいことにチャレンジできたのでここにログ。

今後とも Animetick をよろしくお願い申し上げます。