github+Maven+Android開発でTravisCIの.travis.ymlを書く(SDK22対応)

ひょんなことから、Mavenも知らなかったのに、自作のライブラリをMaven管理にしてTravisCIを使うことになったので、覚書を。適当な部分が多いですが・・・。
また、ここでは.travis.ymlを書くことだけに焦点をあわせてます。

まず、SDK21までは、その他ネット上にある情報でたぶん動くと思います。
ところが、SDK22から、ビルドツールのパスが変更されたり、確認プロンプトが出たりで、それらがそのままでは動かなくなっています。

このため、ymlの記述の中で「SDKのアップデート」をしている場合、注意が必要です。
コピペで中身を確認せず、使っている方は、見事にハマります（笑）
↑しょっぱなとりあえずそのまま動かした人

いずれにしろ、「github+Maven+TravisCI」でAndroid開発をやっていると、同じ.travis.ymlを書くことになるので、これで誰かのお役にたてればと思います。

# とにかく結論
ネット上のサンプルなどから寄せ集めて自分なりに修正したymlを以下に掲載します。
MavenもTravisCIも触り始めてから一週間程度なので、もっといい方法や、間違っているところがあれば、ご指摘お願いします。
また、この記事では取り上げないので、あまり関係ありませんが、注意点として、android-maven-pluginはSDK22対応は3.6.0以上が必要です。（たぶん、3.6.1もすぐに出そうです）

```yaml:.travis.yml
language: java
jdk: oraclejdk6
env:
    matrix:
    - ANDROID_TARGET=android-8   ANDROID_SDKS=android-8,build-tools-17.0.0            ANDROID_BUILD_TOOLS_VERSION=17.0.0 ANDROID_ABI=armeabi
    - ANDROID_TARGET=android-10  ANDROID_SDKS=android-10,build-tools-17.0.0,sysimg-10 ANDROID_BUILD_TOOLS_VERSION=17.0.0 ANDROID_ABI=armeabi
    - ANDROID_TARGET=android-15  ANDROID_SDKS=android-15,build-tools-17.0.0,sysimg-15 ANDROID_BUILD_TOOLS_VERSION=17.0.0 ANDROID_ABI=armeabi-v7a
    - ANDROID_TARGET=android-17  ANDROID_SDKS=android-17,build-tools-17.0.0,sysimg-17 ANDROID_BUILD_TOOLS_VERSION=17.0.0 ANDROID_ABI=armeabi-v7a

before_install:
    # Install base Android SDK
    - sudo apt-get update -qq
    - if [ `uname -m` = x86_64 ]; then sudo apt-get install -qq --force-yes libgd2-xpm ia32-libs ia32-libs-multiarch; fi
    - wget http://dl.google.com/android/android-sdk_r22-linux.tgz
    - tar xzf android-sdk_r22-linux.tgz
    - export ANDROID_HOME=`pwd`/android-sdk-linux
    - export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/build-tools/$ANDROID_BUILD_TOOLS_VERSION

    # Install required Android components.
    - android list sdk --extended
    # Do you accept the license 'android-sdk-license-bcbbd656' [y/n]:
    - echo -e "y\n" > accept.txt
    - android update sdk --filter platform-tools,extra-android-support,$ANDROID_SDKS --no-ui --force < accept.txt

    # PROVISIONAL: changed SDKr22 build-tools path. create symbolic link
    - if [ ! -e ${ANDROID_HOME}/platform-tools/aapt ]; then ln -s ${ANDROID_HOME}/build-tools/$ANDROID_BUILD_TOOLS_VERSION/aapt ${ANDROID_HOME}/platform-tools/aapt; fi
    - if [ ! -e ${ANDROID_HOME}/platform-tools/aidl ]; then ln -s ${ANDROID_HOME}/build-tools/$ANDROID_BUILD_TOOLS_VERSION/aidl ${ANDROID_HOME}/platform-tools/aidl; fi

    # Create and start emulator
    - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
    - emulator -avd test -no-skin -no-audio -no-window &

before_script:
    # Make sure the emulator has started before running tests
    - chmod +x ./wait_for_emulator
    - ./wait_for_emulator

script: mvn install -Pintegration-tests -Dandroid.device=test
```

こんな感じになりました。
また、ここで使っているwait_for_emulatorは以下のような内容です。これはどこかのコピペですみません（汗）
今見たら、改行とかインデントもばらっばらだわ・・・。

```bash:wait_for_emulator
#!/bin/bash

bootanim=""
failcounter=0
until [[ "$bootanim" =~ "stopped" ]]; do
bootanim=`adb -e shell getprop init.svc.bootanim 2>&1`
   echo "$bootanim"
   if [[ "$bootanim" =~ "not found" ]]; then
let "failcounter += 1"
      if [[ $failcounter -gt 3 ]]; then
echo "Failed to start emulator"
        exit 1
      fi
fi
sleep 1
done
echo "Done"
```

TravisCIとgithubの連携は既にセット済み（説明は他に任せて）として、この二つのファイルをプロジェクトのルートあたりに追加してCommitし、Pushすれば処理開始です。
動作確認で手直しする度に、Commit+Pushしなければならないのは、なんとかならないのかな。
まあ、これは、私がやり方知らないだけかも。

# 解説
それでは、簡単に解説していきます。（私も完全に理解しているわけではありませんが）

## ヘッダの定義

```yaml
language: java
jdk: oraclejdk6
```

使用言語がJavaであることと、JDKのバージョンを指定しています。
ネット上の記事ではjdk7を指定しているものもありますが、「Androidは6でいいんじゃね？」という理由から6にしてます。
JDK7がいい人は、`jdk: oraclejdk7`としてください。

## 環境変数の定義

```yaml
env:
    matrix:
    - ANDROID_TARGET=android-8   ANDROID_SDKS=android-8,build-tools-17.0.0            ANDROID_BUILD_TOOLS_VERSION=17.0.0 ANDROID_ABI=armeabi
    - ANDROID_TARGET=android-10  ANDROID_SDKS=android-10,build-tools-17.0.0,sysimg-10 ANDROID_BUILD_TOOLS_VERSION=17.0.0 ANDROID_ABI=armeabi
    - ANDROID_TARGET=android-15  ANDROID_SDKS=android-15,build-tools-17.0.0,sysimg-15 ANDROID_BUILD_TOOLS_VERSION=17.0.0 ANDROID_ABI=armeabi-v7a
    - ANDROID_TARGET=android-17  ANDROID_SDKS=android-17,build-tools-17.0.0,sysimg-17 ANDROID_BUILD_TOOLS_VERSION=17.0.0 ANDROID_ABI=armeabi-v7a
```

envのmatrixで指定すると、複数の環境で同じテストが行えるようになります。
このymlでは、8,10,15,17で動かすように指定してみました。環境が一つで良ければ１行だけ残して他は削ればOKです。
また、以下の４つの環境変数に値を入れています。

+ ANDROID_TARGET
+ ANDROID_SDKS
+ ANDROID_BUILD_TOOLS_VERSION
+ ANDROID_ABI

手元のプロジェクトでは **17しかまともに動いてない** ので、何か間違っている可能性が非常に高いです（汗）
なので、複数環境が必要ない方は、17だけ参考にしてください。
※私自身、まだ設定したばかりで本格的に使ってないので、これについてまだ原因追究してません。

ANDROID_SDKSで何を指定すべきか調べる方法は、後で説明します。（`android list sdk --extended`の所）

また、環境変数を入れ替えた環境で並行して実行されるだけの挙動ですので、自分で好きな名前に好きな値を入れておくことができます。
ここでは、ネット上で見かけるものに加えて、SDK22のビルドツールへのパスをANDROID_BUILD_TOOLS_VERSIONで指定できるようにしています。

## 実行前のインストールの定義
`before_install:`からが、テストを実行する前の準備を行う部分の記述になります。
見る感じ、１行ごとにubuntu系のコマンドですね。

### アップデートと必要なモジュールのインストール

```yaml
    - sudo apt-get update -qq
    - if [ `uname -m` = x86_64 ]; then sudo apt-get install -qq --force-yes libgd2-xpm ia32-libs ia32-libs-multiarch; fi
```

これが必要な理由は、私も明確に把握していないのですが、Android仮想マシンを動かすために必要なものではないかと思います。
いずれにしろ、これによって、テスト環境が最新の状態になります。

### AndroidSDKのインストール
テストに必要なAndroidSDKをテスト環境にインストールします。

```yaml
    - wget http://dl.google.com/android/android-sdk_r22-linux.tgz
    - tar xzf android-sdk_r22-linux.tgz
    - export ANDROID_HOME=`pwd`/android-sdk-linux
    - export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/build-tools/$ANDROID_BUILD_TOOLS_VERSION
```

これは、wgetでSDK配布サイトからlinux用のSDKをダウンロードしてます。
tarコマンドで解凍し、exportで環境変数をセットしています。
ここはlinux系のコマンドがわかれば読めると思います。

具体的なダウンロード先は、
http://developer.android.com/sdk/index.html
から「DOWNLOAD FOR OTHER PLATFORMS」を開いたところの「SDK Tools Only, Linux 32 & 64-bit」の所です。
SDKが新しくなった場合は、このリンク先をコピペして、yml内のファイル名を実ファイル名に合わせて変更しておくと、この後のアップデートが必要ないので、時間の節約、かつ、ちょっとだけTravisCIのサーバにやさしいと思います。最近はやりのエコですね。

### AndroidSDKのコンポーネントの確認
これは、実際には処理を入れる必要がまったくありません。
ですが、SDKの中にどのコンポーネントが入っているか確認するために、このコマンドを入れておくと、ログに出力されて便利です。
環境変数ANDROID_SDKSに値を設定するときの存在確認などに使えます。
過去のSDKがどうだったかわからないのですが、`--extended`のオプションもSDK22で変わったんじゃないかなー？とか思ってます・・・がこれは確認してません！

```text
----------

id: 1 or "platform-tools"

Type: PlatformTool

Desc: Android SDK Platform-tools, revision 17

----------

id: 2 or "build-tools-17.0.0"

Type: BuildTool

Desc: Android SDK Build-tools, revision 17

----------
（～省略～）
```

こんな感じのログが出ますので、idの所の名前が環境変数で指定すべき名前になります。

ANDROID_SDKSで指定しているsysimgやANDROID_ABIで指定しているarmeabi-v7aなどは、x86系CPU向けのAndroid仮想マシンの高速化の話なんかが絡んでいると思います。
ですが、このあたりに私は詳しくないので、実際の所良くわかってません。誰か助けて（汗）

### AndroidSDKのアップデートと確認プロンプト潰し
ここで、AndroidSDKをアップデートします。なので、上でダウンロードしてインストールしていますが、それより新しいSDKが出た場合、自動的に最新のSDKになります。（このため、実質、動くSDKのバージョンはここで決まる）

```yaml
    - echo -e "y\n" > accept.txt
    - android update sdk --filter platform-tools,extra-android-support,$ANDROID_SDKS --no-ui --force < accept.txt
```

アップデートが不要なら、ぶっちゃけ、削って使用SDKを固定してしまっていい気がします。

そして、SDK22で普通にアップデートコマンドを実行すると、確認プロンプトで止まってしまいます。
（SDK21以前を確認していませんが、ネットで検索したサンプルでは、対策しているものが見当たらなかったので、おそらく、SDK21までは無かったんじゃないかと思う）
また、本当はヒアドキュメントでyを送ればよいと思ったのですが、ymlファイル上で記載できるのかわからなかったため、一時的にファイルを作って、それを流し込むようにしました。
なんかもっといい方法がありそうな気がするので、シンプルなやり方があったら教えてください（汗）

※この後出てくる「Android仮想マシンの作成」の記事書きながら気が付いたけど、`echo y | android update sdk`でいい気がしてきた。（未確認）

### 念のためシンボリックリンクの作成
ビルドツールのパスが変わったために、動かなくなっているものがあるかもしれない・・・ということで、未然に防ぐ意味合いを込めてリンク張ってます。ぶっちゃけコレはいらないかもしれません。

```yaml
    - if [ ! -e ${ANDROID_HOME}/platform-tools/aapt ]; then ln -s ${ANDROID_HOME}/build-tools/$ANDROID_BUILD_TOOLS_VERSION/aapt ${ANDROID_HOME}/platform-tools/aapt; fi
    - if [ ! -e ${ANDROID_HOME}/platform-tools/aidl ]; then ln -s ${ANDROID_HOME}/build-tools/$ANDROID_BUILD_TOOLS_VERSION/aidl ${ANDROID_HOME}/platform-tools/aidl; fi
```

### Android仮想マシンの作成

```yaml
    - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
    - emulator -avd test -no-skin -no-audio -no-window &
```

ここでAndroid仮想マシンを作成して実行しています。

## スクリプト実行前の処理
`before_script:`からが、準備完了後にテストを実行する前の処理を行う部分の記述になります。

### Android仮想マシンの起動完了待機

```yaml
    - chmod +x ./wait_for_emulator
    - ./wait_for_emulator
```
Bashファイルに実行権限を付与して、実行してます。
この処理については、私はコピペバンザイですので、説明は割愛します（汗）
まあ、サクっと見た感じだと、`adb -e shell getprop init.svc.bootanim`の戻り値をチェックして判断しているようですね。

## テストスクリプトの指定

```yaml
script: mvn install -Pintegration-tests -Dandroid.device=test
```

やりたかったのは、この１行ですね。
`mvn install` でpom.xmlで指定された通り、テストが動作することになります。

という感じでしょうか。
何か間違いなどありましたら、ガシガシツッコミお願いします。