AndroidアプリをビルドするためのDockerfileを作る

2022-10-16

はじめに

業務で、Slack から GitHub Actions のトリガーを叩き、fastlaneを実行後、Firebase App Distributionにアップロードするというのをやりたいと思い、CI(GitHub Actions)上で動作するイメージを作成しました。結局自分しか使わないかつ、イメージのメンテナンスまで手が回らなくなり辞めちゃったのですが… もちろん、テストも実行できます。

色々試行錯誤したので、どうやってやったか書いています。

実装

M1 Mac で Docker Desktop を使っています。また、Android SDK は再配布がダメなので、試すときは private にして試すなど、ご注意下さい。

ベースのイメージは、Ruby 公式のイメージを使っています。Ruby をベースイメージとしているのは、はじめにでも書きましたが、Slack から GitHub Actions のトリガーを叩き、fastlaneを使ってFirebase App Distributionにアップロードするというのをやっていたためです。が、イメージのメンテナンスなどまで手が回らなくなり結局 Bitrise に移行しましたが…

Ruby のイメージに関して、自分は最初知らなかったのですが、Ruby 公式の方がメンテしているのは、rubylangなのでこれを使っています。オフィシャルの Ruby イメージもあるのですが、そっちは Docker 公式のイメージみたいです。

Dockerfile
FROM --platform=linux/amd64 rubylang/ruby:3.1.2-focal

ENV ANDROID_SDK_REVISION linux-8512546_latest
ENV ANDROID_SDK_ROOT /opt/android-sdk-linux
ENV ANDROID_BUILD_TOOLS_VERSION 32.0.0
ENV ANDROID_COMPILE_SDK 33

RUN apt-get update -y && \
    apt-get upgrade -y && \
    apt-get install zip unzip wget -y && \
    apt-get install openjdk-11-jdk -y

RUN wget https://dl.google.com/android/repository/commandlinetools-${ANDROID_SDK_REVISION}.zip && \
    unzip commandlinetools-${ANDROID_SDK_REVISION}.zip && \
    mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools && \
    mv cmdline-tools ${ANDROID_SDK_ROOT}/cmdline-tools/latest && \
    rm -r commandlinetools-${ANDROID_SDK_REVISION}.zip

ENV PATH ${PATH}:${ANDROID_SDK_ROOT}:${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin

RUN mkdir ~/.android && \
    touch ~/.android/repositories.cfg
RUN yes | sdkmanager --licenses
RUN yes | sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}" \
    "build-tools;${ANDROID_BUILD_TOOLS_VERSION}"

1 行目で--platform=linux/amd64でプラットフォームを指定します。昔は intel の Mac を使っていたので特に指定しなかったのですが、今回は M1 Mac 上でビルドするため指定します。最終的に GitHub Actions で動かしたいのでつけました。

11 行目のopenjdk-11-jdkでは、JDK を入れます。

13-17 行目は、Android のcommandlinetoolsをダウンロード後、解凍します。ダウンロードするバージョンは公式サイトCommand-line tools onlyから最新のバージョンを確認できます。

21-25 行目は、Android SDK と、build-tools をダウンロードします。repositories.cfgファイルは、これがないとWaring が出るため作成します。

実際にイメージを作成します。

イメージを作成
docker build -t docker.pkg.github.com/tatsumi0000/android-playground/android-ci-image:latest .

イメージ作成後、試しに手元でアプリのユニットテストを実行してみます。

ユニットテストを実行
docker run -it -v $PWD:/app docker.pkg.github.com/tatsumi0000/android-playground/android-ci-image:latest bash -c "cd /app && ./gradlew test"

GitHub Packages にイメージを push します。docker loginが済んでいる前提です。

イメージをpushする
docker push docker.pkg.github.com/tatsumi0000/android-playground/android-ci-image:latest

今回は動くかどうかだけ確認できればいいので、CI で使う workflows は以下のようにしています。

.github/workflows/ci.yml
name: unit-test

on:
  - push

jobs:
  test:
    runs-on: ubuntu-latest

    container:
      image: docker.pkg.github.com/tatsumi0000/android-playground/android-ci-image:latest
      credentials:
        username: USER_NAME
        # イメージをprivateで公開するのでPATを発行しsecretsに設定する
        password: ${{ secrets.DOCKER_CONTAINER_REGISTRY_TOKEN }}

    steps:
      - uses: actions/checkout@v2

      - name: "unit test"
        run: |
          ./gradlew test

最後に

Android の CI に使う Dockerfile 作成から、実際に GitHub Actions で動かしました。

実際に運用していたときは、GitHub Enterprise Server 上で動かしていて、まだキャッシュ機能がありませんでした。そのため、イメージ作成時に、ライブラリなどのキャッシュも含めることで、CI 時間を減らすようにしました(Dockerfile の最後にテストのステップを追加することで、キャッシュも含めました)。他にもイメージのキャッシュ更新も自動化していました。実装方法は単純で、master ブランチに対してpathsapp/build.gradleを指定し、差分があると、CI 上でイメージを作成後、GitHub Packages に push するようにしていました。

Docker や CI は好きなのでもっと勉強していきたいなと思います。

参考サイト

Tatsumi0000

Written by Tatsumi0000 モバイル開発が好きなエンジニアのブログです. GitHub

Copyright © 2023, Tatsumi0000 All Rights Reserved.