GitLab CIでAndroidStudioプロジェクトのCI環境を構築する

AndroidStudioプロジェクトの
- ビルド
- fabricでのBeta配信
- GooglePlayStoreへのアップロード
をCI環境で実現しました。

# 実行環境
* GitLab CE 9.3.9
* GitLab-CI 9.3.9
* Gradle 3.2
* Android SDK Tools 26.0.2
* Compile SDK 25
* Build tools 25.0.2

# Runnerマシンの構築
利用したMacは10.12.6

### CI Runnerのインストール
GitLab本家のドキュメント通りに実行しました。
https://docs.gitlab.com/runner/install/osx.html

### RunnerをGitLabに登録
こちらも本家GitLabのドキュメント通りに実行し問題ありませんでした。
https://docs.gitlab.com/runner/register/index.html#macos

そのほか、[補足事項](http://qiita.com/watanave/items/05f66de62acf4217a63f#runnerをgitlabに登録a)

参考までに、Runnerの登録設定

```shell-session
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
{gitlabのURL}

Please enter the gitlab-ci token for this runner:
{Runnerのtoken。調べ方は上のリンク (補足事項)}

Please enter the gitlab-ci description for this runner:
{ランナーの説明}

Please enter the gitlab-ci tags for this runner (comma separated):
ci-for-android

Whether to run untagged builds [true/false]:
[false]: 

Whether to lock Runner to current project [true/false]:
[false]: 

Registering runner... succeeded                     runner=cqapF6Xd
Please enter the executor: docker+machine, docker-ssh+machine, parallels, ssh, shell, virtualbox, kubernetes, docker, docker-ssh:
docker

Please enter the default Docker image (e.g. ruby:2.1):
openjdk:8-jdk

Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded! 
```

# ジョブの記述
.gitlab-ci.ymlという名前のファイルにRunnerに実行させたい処理(job)を記述します。
このファイルはリポジトリのルートに置く必要があるようです。

GitLab本家のブログにサンプルのymlが公開されています。
https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/
が、最新のSDK Toolを指定してビルドすることはできません。
事前準備のところでこけます。


結局、私は以下のようにしました。
### before_script

```yaml
image: openjdk:8-jdk

variables:
  ANDROID_COMPILE_SDK: "25"
  ANDROID_BUILD_TOOLS: "25.0.2"
  ANDROID_SDK_TOOLS: "3859397"
  SDK_ROOT: "/sdk"
  
before_script:
  - apt-get --quiet update --yes
  - apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1
  - wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS}.zip
  - unzip android-sdk.zip -d ${SDK_ROOT}
  - mkdir -p /root/.android
  - touch /root/.android/repositories.cfg
  - mkdir -p ${SDK_ROOT}/licenses
  - cp ./android-sdk-license ${SDK_ROOT}/licenses/
  - ${SDK_ROOT}/tools/bin/sdkmanager --package_file=./packages.txt
  - export ANDROID_HOME=${SDK_ROOT}
  - export ANDROID_NDK_HOME=${SDK_ROOT}/ndk-bundle/
  - export PATH=$PATH:${SDK_ROOT}/platform-tools/
  - touch local.properties
  - echo "sdk.dir=${ANDROID_HOME}" >> local.properties
  - echo "ndk.dir=${ANDROID_NDK_HOME}" >> local.properties
```

#### SDK Toolsの指定
AndroidStudioのダウンロードページより
https://developer.android.com/studio/index.html
この数字を変数化しました。
![スクリーンショット 2017-08-31 10.19.13.png](https://qiita-image-store.s3.amazonaws.com/0/14646/2b5de6ac-98d9-b16f-58f8-618b1fc40be6.png)

```yaml
variables:
  ANDROID_SDK_TOOLS: "3859397"
# 中略
before_script:
  - wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS}.zip
```


#### repositories.cfg could not be loaded.
以下のようなワーニングが出ます。

```shell-session
Warning: File /root/.android/repositories.cfg could not be loaded.
```

ファイル自体を作成することでワーニングを回避しました。
それ以上は深追いせず。

```yaml
before_script:
  #中略
  - mkdir -p /root/.android
  - touch /root/.android/repositories.cfg
```

#### AndroidSDKのダウンロード&インストール
SDK Toolsに同梱されているsdkmanagerを使い、AndroidSDKをダウンロードを試行します。
が、利用規約への同意がなされていなければ、インストールすることができません。

```shell-session
The following packages can not be installed since their licenses or those of the packages they depend on were not accepted:
```

sdkmanagerの --licenses オプションが使えそうと思ったのですが、CUIで都度"y"を入力する仕様のようでCI環境には適しませんでした。
結局、開発マシンに保存されているライセンスへの同意が記述されたファイルをコピーすることで回避しました。

また、インストールするSDKの指定方法など、こちらの記事を参考にしました。
http://y-anz-m.blogspot.jp/2017/05/android-sdkmanager.html

私の場合はNDKを含め、このようにパッケージの指定をしました。

```text
platform-tools
build-tools;25.0.2
platforms;android-25
extras;android;m2repository
extras;google;m2repository
extras;google;google_play_services
ndk-bundle
lldb;2.3
cmake;3.6.4111459
```

#### NDKのパスを通す
続いて、以下のようなエラーが発生しました。

```shell-session
NDK is missing a "platforms" directory.
If you are using NDK, verify the ndk.dir is set to a valid NDK directory.  It is currently set to /builds/XXXX/XXXX/sdk/ndk-bundle.
If you are not using NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties to remove this warning.
```

NDKを使用していないプロジェクトにもかかわらず...です。
こちらはAndroid gradle plugin 2.3の問題のようです。
https://github.com/requery/requery/issues/467
Android gradle plugin 2.2へダウングレードすることで回避できるようですが、
NDKを扱うプロジェクトもCI環境に載せる予定だったため、NDKのパスを正しく指定することで回避しました。

```yaml
variables:
  SDK_ROOT: "/sdk"
  
before_script:
  # 中略
  - export ANDROID_HOME=${SDK_ROOT}
  - export ANDROID_NDK_HOME=${SDK_ROOT}/ndk-bundle/
  - touch local.properties
  - echo "sdk.dir=${ANDROID_HOME}" >> local.properties
  - echo "ndk.dir=${ANDROID_NDK_HOME}" >> local.properties
```

※ local.propertiesをリポジトリで管理している場合は、この限りではありません。

### デバックビルドしてみる

gradleでビルドしてみます。
私の環境では、これでビルドに成功しました。

```yaml
image: openjdk:8-jdk

variables:
  ANDROID_COMPILE_SDK: "25"
  ANDROID_BUILD_TOOLS: "25.0.2"
  ANDROID_SDK_TOOLS: "3859397"
  SDK_ROOT: "/sdk"
  
before_script:
  - apt-get --quiet update --yes
  - apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1
  - wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS}.zip
  - unzip android-sdk.zip -d ${SDK_ROOT}
  - mkdir -p /root/.android
  - touch /root/.android/repositories.cfg
  - mkdir -p ${SDK_ROOT}/licenses
  - cp ./android-sdk-license ${SDK_ROOT}/licenses/
  - ${SDK_ROOT}/tools/bin/sdkmanager --package_file=./packages.txt
  - export ANDROID_HOME=${SDK_ROOT}
  - export ANDROID_NDK_HOME=${SDK_ROOT}/ndk-bundle/
  - export PATH=$PATH:${SDK_ROOT}/platform-tools/
  - touch local.properties
  - echo "sdk.dir=${ANDROID_HOME}" >> local.properties
  - echo "ndk.dir=${ANDROID_NDK_HOME}" >> local.properties

stages:
  - build
  
build:
  stage: build
  script:
    - ./gradlew assembleDebug
  tags:
    - ci-for-android
```

#### タグの指定について

```yaml
  tags:
    - ci-for-android
```

[こちらの記事](http://qiita.com/watanave/items/05f66de62acf4217a63f#ジョブの記述)を参照してください。