0
1

More than 3 years have passed since last update.

今やってるAndroidプロジェクトにgitlabciを導入してみた

Last updated at Posted at 2020-11-06

前回やったことと今回やること

前回は今回の事前準備として、手動でDockerコンテナからAndroidアプリのビルドを行いました

今回は

  • gitlabciを使ってCommit時に自動ビルドを実行する
  • ブランチごとにビルドタイプとフレーバーを指定する
  • VersionCodeにgitlabciのJobIDを割り当てる

ここまでやっていきたいと思います

.gitlab-ci.yml作成

まずはgitlabciのCI/CDの設定ファイルである.gitlab-ci.yml を作ります

作り方はとてもかんたんで、

  • リポジトリのファイル一覧のページから,「+」→「New File」を選択
  • Templateで「.gitlab-ci.yml」「Android」を選択

すると、下記のファイルが作成されます

.gitlab-ci.yml
# This file is a template, and might need editing before it works on your project.
# Read more about this script on this blog post https://about.gitlab.com/2018/10/24/setting-up-gitlab-ci-for-android-projects/, by Jason Lenny
# If you are interested in using Android with FastLane for publishing take a look at the Android-Fastlane template.

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

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

assembleDebug:
  stage: build
  script:
    - ./gradlew assembleDebug
  artifacts:
    paths:
      - app/build/outputs/

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

実はこれでほぼほぼできています笑
というか、前回手動でやったときもここを参考にしてもらいました

とはいえいくつか変えないといけないところがあるので、そちらの解説をしていきます

イメージ

.gitlab-ci.yml
image: openjdk:8-jdk

ここはそのままで大丈夫です

変わった処理をするので自分で作ったDockerfileを使いたい場合や、すでに誰かが作っているものを流用したい場合は変更してください

今回は定石のコマンドしか叩かないのでここはそのまま

変数

.gitlab-ci.yml
variables:
  ANDROID_COMPILE_SDK: "28"
  ANDROID_BUILD_TOOLS: "28.0.2"
  ANDROID_SDK_TOOLS: "4333796"

ここはビルドするアプリの設定によって変更する必要があります
一番下はビルド時に使うツールのバージョンなのでそのままで行きますが、古すぎると使えないコマンドがあるので注意してください

準備コマンド

.gitlab-ci.yml
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

ツールのインストールや環境変数の設定を行います

今回は署名の際にビルドツールに入っているライブラリを使用するので下記を追記します

.gitlab-ci.yml
- export PATH=$PATH:$PWD/android-sdk-linux/build-tools/${ANDROID_BUILD_TOOLS}/

実装部

ここからがメインです

Templateでは

  1. リントチェック
  2. ビルド
  3. テスト

と行っていましたが、今回は

  1. ビルド
  2. 署名

の順番で実施します(処理としては一まとまりです)

ビルド処理

  • ここではdevelopフレーバーでビルドを行っています
.gitlab-ci.yml
test_assemble:
  stage: build
  script:
    - ./gradlew assembleRelease
  artifacts:
    paths:
      - app/build/outputs/
  • stage

    • デフォルトでbuildとtestが用意されており、それ以外を使用する場合はこの前に「stages」で定義する必要があります 今回はbuildのみを使用するため割愛します
  • script

    • 今回は署名付きのリリースビルドを行います
    • ひとまず全フレーバーでビルドを行います(runnerのスペックが足らない場合は落ちる可能性あり)
  • artifacts

    • デフォルトではフォルダが出力されます。今回はそのままです

署名処理

  • scriptに署名処理を追記します
.gitlab-ci.yml
test_assemble:
  script:
    - ./gradlew assembleRelease
    - echo [jksファイルをbase64でエンコードしたもの] | base64 -d > my.keystore
    - apksigner sign --ks my.keystore -v --v2-signing-enabled true --ks-key-alias [エイリアス名] --ks-pass pass:[キーストアのパスワード] --key-pass pass:[キーのパスワード] --out app-develop_-release.apk $(pwd)/app/build/outputs/apk/develop_/release/app-develop_-release-unsigned.apk
  • jksファイルをbase64でエンコードしたものをデコードし、keyファイルとして出力します
  • apksignerというライブラリを使ってビルドしています。必要な情報をオプションで記載しています

apksignerに関しては公式こちらを参考にさせていただきました

※署名前のファイルは末尾が〇〇-unsigned.apkとなるので注意(ここでだいぶつまづきました(泣))

環境変数化

パスワードや署名ファイルを直書きするのはセキュリティ的に問題ですので、gitlabciの設定にあるVariables機能を使います

横のメニューから「Setting」→「CI/CD」→「Variables」の「Expand」をクリック
SnapCrab_NoName_2020-11-5_14-55-14_No-00.png

このような画面が開きます(すでに変数設定済み)

緑色の「Add Variable」を押すと登録画面が開きます

SnapCrab_NoName_2020-11-5_14-57-11_No-00.png

  • Key
    • 環境変数名
  • Value
    • 環境変数の値
  • Type
    • 変数orファイル(今回はデフォルト)
  • Environment scope
    • スコープの設定(今回はデフォルト)
  • Flags
    • Protect variable
      • プロテクトブランチでのみ有効になります(今回はチェックしない)
    • Mask variable
      • ログに出力されなくなります(今回はチェックしない)

上記で

  • KEY_ALIAS
    • エイリアス名
  • KEY_PASSWORD
    • キーのパスワード
  • KEYSTORE_FILE
    • jksファイルをbase64でエンコードしたもの
  • KEYSTORE_PASSWORD
    • キーストアのパスワード

をそれぞれ設定します

設定後、.gitlab-ci.ymlに戻り、scriptを変更します

.gitlab-ci.yml
test_assemble:
  script:
    - ./gradlew assembleRelease
    - echo ${KEYSTORE_FILE} | base64 -d > my.keystore
    - apksigner sign --ks my.keystore -v --v2-signing-enabled true --ks-key-alias ${KEY_ALIAS} --ks-pass pass:${KEYSTORE_PASSWORD} --key-pass pass:${KEY_PASSWORD} --out app-${FLAVOR}_-release.apk $(pwd)/app/build/outputs/apk/${FLAVOR}_/release/app-${FLAVOR}_-release-unsigned.apk

Variablesを使用する場合は$(ドルマーク)を使います(括弧はなくてもよい)

VersionCodeにJobIDを指定

build.gradleに記載しているVersionCodeをいちいち手動で書き換えるのはめんどくさいので、CIから動的に変更するようにしたいと思います
場合によってはversionNameの方も書き換えますが、今回は省略します。

流れとしては

  • build.gradleにtaskを追加
  • gitlabciにデフォルトである環境変数を呼ぶ
  • ciからtaskを呼び、上記パラメータを渡す

という感じになります

build.gradleにCIのVariablesを取得する処理を追加

build.gradle(appじゃない方)にVersionCodeを動的に変更するタスクを追加します
こちらを参考にさせていただきました

build.gradle
task setJobNumber {
    if (project.hasProperty("num")) {
        def pattern = "versionCode (\\d+)"
        def manifestFile = file("./app/build.gradle")
        def manifestText = manifestFile.getText()

        def num = project.property("num")
        def manifestContent = manifestText.replaceAll(pattern, "versionCode " + num)
        manifestFile.write(manifestContent)
    }
}

numというプロパティを実行時に渡してあげることで、ビルド前にVersionCodeを書き換える処理を実現します

gitlabciで準備されている環境変数について

上記では自分でkey-valueを設定し、環境変数を追加しましたが、gitlabciにはciで発行されるIDやTokenを取得するための環境変数が準備されています
結構種類は豊富です。こちらを参考にしてください

今回はCI_JOB_IDを使用します

上記処理を実行するコマンドをymlに追加

上記で作成したタスクを呼び、パラメータを付与します

.gitlab-ci.yml
test_assemble:
  script:
    - ./gradlew setJobNumber -Pnum=${CI_JOB_ID}

ブランチごとにフレーバーを指定する

  • 上記処理をコピペして各ブランチごとに処理を作れば実現可能ではあるが、コマンドが重複しがち
  • paramを使って処理のTemplateを作り、extendsを使用して重複しないように記載していく

先ほど作成したtest_assembleをテンプレート部と変数代入部に分けるイメージです

.gitlab-ci.yml
.param_build:
  script:
    - ./gradlew setJobNumber -Pnum=${CI_JOB_ID}
    - ./gradlew assemble${FLAVOR}_Release
    - echo ${KEYSTORE_FILE} | base64 -d > my.keystore
    - apksigner sign --ks my.keystore -v --v2-signing-enabled true --ks-key-alias ${KEY_ALIAS} --ks-pass pass:${KEYSTORE_PASSWORD} --key-pass pass:${KEY_PASSWORD} --out app-${FLAVOR}_-release.apk $(pwd)/app/build/outputs/apk/${FLAVOR}_/release/app-${FLAVOR}_-release-unsigned.apk
  artifacts:
    paths:
      - app-${FLAVOR}_-release.apk

まずは.param_buildに先程作った処理を記載し、環境ごとに変わる値を環境変数に置き換えます(ここではFLAVORとしています)

.gitlab-ci.yml
develop_assemble:
  stage: build
  only:
    - develop
  variables:
    FLAVOR: develop
  extends:
    - .param_build

#以下に他のブランチが続く

初登場の3つを説明します

  • only
    • こちらでブランチを指定します
    • 今回はdevelopブランチにcommitしたときに実行したいのでdevelopとしています
  • variables
    • 環境変数をここで設定します
    • 今回はFLAVORをdevelopとして設定します
  • extends

    • 使うテンプレートを指定します
    • 今回は当然.param_buildです
  • 注意点としては、.param_buildで指定されている処理を書いてしまうと完全に上書きされてしまいます

    • 例えばscriptをこっちに書いてしまうと、.param_buildの処理を上書きしてしまうので、.param_buildのscript処理は実行されなくなります

最終成果物がこちら

.gitlab-ci.yml
# This file is a template, and might need editing before it works on your project.
# Read more about this script on this blog post https://about.gitlab.com/2018/10/24/setting-up-gitlab-ci-for-android-projects/, by Jason Lenny
# If you are interested in using Android with FastLane for publishing take a look at the Android-Fastlane template.

image: openjdk:8-jdk

variables:
  ANDROID_COMPILE_SDK: "28"
  ANDROID_BUILD_TOOLS: "29.0.3"
  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/
  - export PATH=$PATH:$PWD/android-sdk-linux/build-tools/${ANDROID_BUILD_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

.param_build:
  tags:
    - Android
  script:
    - ./gradlew setJobNumber -Pnum=${CI_JOB_ID}
    - ./gradlew assemble${FLAVOR}_Release
    - echo ${KEYSTORE_FILE} | base64 -d > my.keystore
    - apksigner sign --ks my.keystore -v --v2-signing-enabled true --ks-key-alias ${KEY_ALIAS} --ks-pass pass:${KEYSTORE_PASSWORD} --key-pass pass:${KEY_PASSWORD} --out app-${FLAVOR}_-release.apk $(pwd)/app/build/outputs/apk/${FLAVOR}_/release/app-${FLAVOR}_-release-unsigned.apk
  artifacts:
    paths:
      - app-${FLAVOR}_-release.apk

develop_assemble:
  stage: build
  only:
    - develop
  variables:
    FLAVOR: develop
  extends:
    - .param_build

#以下に他のブランチが続く

一つ補足しておくと、.param_buildのtagsでrunnerの指定をしています
プロジェクトに複数のrunnerが登録されている場合、どのrunnerでビルドを行うかをTagによって指定することができます

こちらを各ブランチにcommitすると、指定したビルドが動き、「CI/CD」→「Pipeline」から生成物をダウンロードできるはずです

確認

署名ができているかどうかは下記コマンドで確認できます

keytool -printcert -jarfile (APK名)

中身の確認はAndroid Studioのapkanalyzerで、手動ビルドとの比較が可能です

追記

今回はビルド後に後付の署名を行いましたが、ビルド時に署名情報を付与することが可能です

試してはみたのですが、何故かうまく行かず、このままでは気持ち悪いので、少し調査してみようと思います
分かり次第記事にしようと思っております

長々とご覧頂きありがとうございました

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1