前回やったことと今回やること
前回は今回の事前準備として、手動でDockerコンテナからAndroidアプリのビルドを行いました
今回は
- gitlabciを使ってCommit時に自動ビルドを実行する
- ブランチごとにビルドタイプとフレーバーを指定する
- VersionCodeにgitlabciのJobIDを割り当てる
ここまでやっていきたいと思います
.gitlab-ci.yml作成
まずはgitlabciのCI/CDの設定ファイルである.gitlab-ci.yml を作ります
作り方はとてもかんたんで、
- リポジトリのファイル一覧のページから,「+」→「New File」を選択
- Templateで「.gitlab-ci.yml」「Android」を選択
すると、下記のファイルが作成されます
# 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
実はこれでほぼほぼできています笑
というか、前回手動でやったときもここを参考にしてもらいました
とはいえいくつか変えないといけないところがあるので、そちらの解説をしていきます
イメージ
image: openjdk:8-jdk
ここはそのままで大丈夫です
変わった処理をするので自分で作ったDockerfileを使いたい場合や、すでに誰かが作っているものを流用したい場合は変更してください
今回は定石のコマンドしか叩かないのでここはそのまま
変数
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
ツールのインストールや環境変数の設定を行います
今回は署名の際にビルドツールに入っているライブラリを使用するので下記を追記します
- export PATH=$PATH:$PWD/android-sdk-linux/build-tools/${ANDROID_BUILD_TOOLS}/
実装部
ここからがメインです
Templateでは
- リントチェック
- ビルド
- テスト
と行っていましたが、今回は
- ビルド
- 署名
の順番で実施します(処理としては一まとまりです)
ビルド処理
- ここではdevelopフレーバーでビルドを行っています
test_assemble:
stage: build
script:
- ./gradlew assembleRelease
artifacts:
paths:
- app/build/outputs/
-
stage
- デフォルトでbuildとtestが用意されており、それ以外を使用する場合はこの前に「stages」で定義する必要があります 今回はbuildのみを使用するため割愛します
-
script
- 今回は署名付きのリリースビルドを行います
- ひとまず全フレーバーでビルドを行います(runnerのスペックが足らない場合は落ちる可能性あり)
-
artifacts
- デフォルトではフォルダが出力されます。今回はそのままです
署名処理
- scriptに署名処理を追記します
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」をクリック
このような画面が開きます(すでに変数設定済み)
緑色の「Add Variable」を押すと登録画面が開きます
- Key
- 環境変数名
- Value
- 環境変数の値
- Type
- 変数orファイル(今回はデフォルト)
- Environment scope
- スコープの設定(今回はデフォルト)
- Flags
- Protect variable
- プロテクトブランチでのみ有効になります(今回はチェックしない)
- Mask variable
- ログに出力されなくなります(今回はチェックしない)
- Protect variable
上記で
- KEY_ALIAS
- エイリアス名
- KEY_PASSWORD
- キーのパスワード
- KEYSTORE_FILE
- jksファイルをbase64でエンコードしたもの
- KEYSTORE_PASSWORD
- キーストアのパスワード
をそれぞれ設定します
設定後、.gitlab-ci.ymlに戻り、scriptを変更します
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を動的に変更するタスクを追加します
こちらを参考にさせていただきました
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に追加
上記で作成したタスクを呼び、パラメータを付与します
test_assemble:
script:
- ./gradlew setJobNumber -Pnum=${CI_JOB_ID}
ブランチごとにフレーバーを指定する
- 上記処理をコピペして各ブランチごとに処理を作れば実現可能ではあるが、コマンドが重複しがち
- paramを使って処理のTemplateを作り、extendsを使用して重複しないように記載していく
先ほど作成したtest_assembleをテンプレート部と変数代入部に分けるイメージです
.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としています)
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処理は実行されなくなります
最終成果物がこちら
# 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で、手動ビルドとの比較が可能です
追記
今回はビルド後に後付の署名を行いましたが、ビルド時に署名情報を付与することが可能です
試してはみたのですが、何故かうまく行かず、このままでは気持ち悪いので、少し調査してみようと思います
分かり次第記事にしようと思っております
長々とご覧頂きありがとうございました