【GitLab-CI】Androidアプリの自動バージョニング

GitLab PipelineでのAndroidアプリの自動バージョニングについて、調べてまとめた結果です。

##目的
GitLabにPushする度にPipelineで毎回ビルドバージョンをインクリメントし、ビルドを行う。

##方法
####サンプル
https://gitlab.com/rexiaxm7/android-versioning-sample

####1. GitLab Pipelineでメジャーバージョンとマイナーバージョンを環境変数に持たせる。
GitLab > Settings > CI/CD > Environment variables に定義します。
今回は MAJOR_VERSION と MINOR_VERSIONという名前で定義しています。
(1.1系にしたい場合は手動で値を変更する必要があります。)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/335934/4ef02e48-fedf-a0e7-a0ee-23c36c219663.png)



####2. Pipelineが実行される毎にインクリメントされるCI_PIPELINE_IIDをビルドバージョンとして、Gradleにバージョンを渡してビルドを行う。

対象Repository下で下記の 「+」> New fileを選択する。 
![image.png](https://qiita-image-store.s3.amazonaws.com/0/335934/ab1e9d11-827a-27cb-b5a2-33c0066b055e.png)

Templateで「.gitlab-ci.yml」と「Android」を選択し、commitする。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/335934/ea0853c6-4086-06c7-d3f6-dc3d78ebe2c5.png)

下記ファイルのコメント箇所を変更する。
その後、Pipelineが動作しBuildされる。

```.gitlab-ci.yml

image: openjdk:8-jdk

variables:
  ANDROID_COMPILE_SDK: "28"
  ANDROID_BUILD_TOOLS: "28.0.2"
  ANDROID_SDK_TOOLS:   "4333796"

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 -d android-sdk-linux android-sdk.zip
  - echo y | android-sdk-linux/tools/bin/sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}" >/dev/null
  - echo y | android-sdk-linux/tools/bin/sdkmanager "platform-tools" >/dev/null
  - echo y | android-sdk-linux/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}" >/dev/null
  - export ANDROID_HOME=$PWD/android-sdk-linux
  - export PATH=$PATH:$PWD/android-sdk-linux/platform-tools/
  - chmod +x ./gradlew
  # temporarily disable checking for EPIPE error and use yes to accept all licenses
  - set +o pipefail
  - yes | android-sdk-linux/tools/bin/sdkmanager --licenses
  - set -o pipefail

stages:
  - build
  - test

lintDebug:
  stage: build
  script:
    - ./gradlew -Pci --console=plain :app:lintDebug -PbuildDir=lint

assembleDebug:
  stage: build
  script:
  # P + 変数名とすることが重要
    - ./gradlew assembleDebug -PmajorVersion=$MAJOR_VERSION -PminorVersion=$MINOR_VERSION -PbuildVersion=$CI_PIPELINE_IID
  artifacts:
  # 生成物にもバージョンを追加するようにした。
    name: "sample_${MAJOR_VERSION}.${MINOR_VERSION}.${CI_PIPELINE_IID}"
    paths:
    - app/build/outputs/

debugTests:
  stage: test
  script:
    - ./gradlew -Pci --console=plain :app:testDebug
```

```build.gradle
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

// 引数を受け取る。引数がない場合は 1.0.0
ext {
    majorVersion = project.hasProperty('majorVersion') ? Integer.parseInt(project.majorVersion) : 1
    minorVersion = project.hasProperty('minorVersion') ? Integer.parseInt(project.minorVersion) : 0
    buildVersion = project.hasProperty('buildVersion') ? Integer.parseInt(project.buildVersion) : 0
}

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.android_versioning_sample"
        minSdkVersion 23
        targetSdkVersion 28
        // versionCodeとVersionNameを可変に変更。versionCodeの最大値は2147483647
        versionCode (majorVersion * 100000 + minorVersion * 1000 + buildVersion)
        versionName "$majorVersion.$minorVersion.$buildVersion"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
```

buildされたアプリの結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/335934/eb212c58-6b20-4869-fb9f-9fb1e4eec10b.png)
##ハマった箇所
Gradleに引数を渡す際の引数名はプレフィックスとして「P」をつける必要があった。
**build.gradle内では 「majorVersion」としているが、.gitlab-ci.ymlでは -PmajorVersionとする必要がある。**
(Gradleではなく、GradleでAndroidアプリをビルドする際の特殊なもの？ご存知の方がいらっしゃれば、コメントにて教えていただけると助かります。)

##問題点
docker imageを展開してから、Android-SDKを毎回DLしてくるため、ビルドが非常に遅い。
GitLabではPrivateなDocker Repositoryも使用可能なため、Android-SDKを組み込んだ状態のdocker imageをそこに配置することで高速化が図れると思います。
(Android-SDKの再配布はライセンス違反のようなので、Publicな配置は厳禁です。)

##まとめ
GitLabでのAndroidバージョニングの情報がなかったのでやってみました。
ビルド速度、ビルドバージョンが任意でのリセット方法が見つかり次第、更新します。