• トップ
  • ブログ一覧
  • 【Android】GitHub ActionsからワンクリックでFirebase App Distributionにアプリをデプロイする
  • 【Android】GitHub ActionsからワンクリックでFirebase App Distributionにアプリをデプロイする

    こー(エンジニア)こー(エンジニア)
    2025.07.09

    IT技術

    はじめに

    こんにちは!株式会社ライトコードの福岡本社でモバイルエンジニアやってる こー です!

    featureImg2021.11.05YOUは何しにライトコードへ?〜こーくん編〜プロジェクト内で安心感を与えられる存在になりたい!今回は、弊社のエンジニアである高さんにフィーチャー!技術力に定評のあ...

    前回は、GitHub Actionsを使ってAndroidアプリのバージョン番号(versionNameversionCode)を自動で更新し、プルリクエストを作成するワークフローについて解説しました。

    前回の記事(まだの方はこちらからどうぞ!)
    featureImg2025.02.07【Android】GitHub Actionsでアプリのバージョン情報を更新するはじめにこんにちは!株式会社ライトコードの福岡本社でモバイルエンジニアやってる こー です!現在、個人開発しているAn...

    開発中では、テスターやチームメンバーに対して動作確認用としてAPKファイルを配信することが多くあると思います。

    ですが、

    1. Android Studioで「Build > Generate Signed Bundle / APK」を選択し、
    2. リリース用のAPKファイルを生成し、
    3. Firebaseコンソールを開き、App Distributionのページに移動し、
    4. 先ほど生成したAPKファイルをドラッグ&ドロップし、
    5. リリースノートを記入して、テスターに配布する

    という一連の作業、一度や二度ならまだしも、開発が活発になればなるほど、何度も繰り返すことになります。

    正直面倒くさいですし、手作業が増えれば署名設定を間違えたり、アップロードするAPKを間違えたりなどのヒューマンエラーを引き起こす可能性も高くなります。

    そこで今回の後編では、前編で自動化したバージョン更新の仕組みをさらに発展させ、GitHub Actionsの画面からワンクリックするだけで、バージョンアップからAPKのビルド、そしてFirebase App Distributionへのデプロイまでを全自動で行うワークフローについて解説していきます。

    それでは見ていきましょう!

    今回構築するワークフローの全体像

    今回目指すのは、バージョンアップの種類に応じて3つのワークフローを用意し、それぞれを手動で実行できるようにします。

    • Deploy To App Distribution - Major:メジャーバージョンを上げてデプロイ
    • Deploy To App Distribution - Minor:マイナーバージョンを上げてデプロイ
    • Deploy To App Distribution - Patch:パッチバージョンを上げてデプロイ

    これらのワークフローは、GitHubのActionsタブから「Run Workflow」ボタンを押すだけで、以下の処理をすべて自動で行ってくれます。

    1. バージョンの更新: build.gradle.kts内のversionNameversionCodeをインクリメントします。
    2. リリースAPKのビルド: アプリケーションをビルドし、署名付きのリリースAPKを生成します。
    3. Firebase App Distributionへのデプロイ: 生成されたAPKをApp Distributionにアップロードし、テスターに配布します。
    4. 後処理: 次のリリースに備えて、変更内容を記録したプルリクエストを作成します。

    それでは、この仕組みがどのように実現されているのか、実際のGitHub Actionsのワークフローファイルを詳しく見ていきましょう。

    ワークフローファイルの解説

    3つのワークフロー(Major/Minor/Patch)は、更新するバージョンの種類が違うだけで、基本的な構造はほぼ同じです。

    ここでは代表として、一番利用頻度が高いであろう deploy-release-apk-patch.yml の中身を、順次解説していきます。

    1#/.github/workflows/deploy-release-apk-patch.yml
    2name: Deploy To App Distribution - Patch
    3
    4on: [workflow_dispatch]
    5
    6jobs:
    7  deploy-release-apk:
    8    runs-on: ubuntu-latest
    9    steps:
    10      - uses: actions/checkout@v2
    11        with:
    12          ref: 'release'
    13
    14      - name: set up JDK 17
    15        uses: actions/setup-java@v2
    16        with:
    17          java-version: '17'
    18          distribution: 'temurin'
    19          cache: gradle
    20
    21      - name: Grant Permission gradlew
    22        run: chmod +x gradlew
    23
    24      - name: Make google-service.json
    25        env:
    26          GOOGLE_SERVICE: ${{ secrets.GOOGLE_SERVICE_JSON }}
    27        run: echo $GOOGLE_SERVICE | base64 --decode --ignore-garbage > ./app/google-services.json
    28
    29      - name: Bump Patch Version
    30        run: ./gradlew bumpPatchVersion
    31
    32      - name: Get Version
    33        run: |
    34          echo "::set-output name=VERSION_CODE::$(./gradlew -q printVersionCode)"
    35          echo "::set-output name=VERSION_NAME::$(./gradlew -q printVersionName)"
    36        id: version
    37
    38      - name: Building Release APK
    39        env:
    40          ENV_SIGN_KEYSTORE_BASE64: ${{ secrets.ENV_SIGN_KEYSTORE_BASE64 }}
    41          ENV_SIGN_KEY_ALIAS: ${{ secrets.ENV_SIGN_KEY_ALIAS }}
    42          ENV_SIGN_KEY_PASSWORD: ${{ secrets.ENV_SIGN_KEY_PASSWORD }}
    43          ENV_SIGN_STORE_PASSWORD: ${{ secrets.ENV_SIGN_STORE_PASSWORD }}
    44        run: ./gradlew assembleRelease
    45
    46      - name: Deploy to App Distribution
    47        uses: wzieba/Firebase-Distribution-Github-Action@v1
    48        with:
    49          appId: ${{ secrets.FIREBASE_APP_ID }}
    50          serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}
    51          groups: release
    52          releaseNotesFile: RELEASE_NOTE.md
    53          file: ./app/build/outputs/apk/release/app-release.apk
    54
    55      - name: Init RELEASE_NOTE.md
    56        run: cat RELEASE_NOTE.init.md > RELEASE_NOTE.md
    57
    58      - name: Create Pull Request
    59        uses: peter-evans/create-pull-request@v6
    60        with:
    61          token: ${{ secrets.GITHUB_TOKEN }}
    62          branch: after-released-${{ steps.version.outputs.VERSION_NAME }}-${{ steps.version.outputs.VERSION_NAME }}
    63          base: release
    64          title: "Released version: `${{ steps.version.outputs.VERSION_NAME }}` / `${{ steps.version.outputs.VERSION_CODE }}`"
    65          commit-message: "Released version: `${{ steps.version.outputs.VERSION_NAME }}` / `${{ steps.version.outputs.VERSION_CODE }}`"

    手動実行のトリガー設定

    1on: [workflow_dispatch]

    workflow_dispatch を指定することで、このワークフローはGitHubのUI(Actionsタブ)から手動で実行できるようになります。

    特定のブランチへのプッシュやプルリクエストをトリガーにしないことで、開発者の任意のタイミングでデプロイを実行できる柔軟性を確保しています。

    ビルド & デプロイ処理

    ここから実際のデプロイ処理内容について解説していきます。

    jobs セクションで deploy-release-apk という名前のジョブを定義しています。

    runs-on: ubuntu-latest で、このジョブが最新のUbuntu環境で実行されることを指定しています。

    では、steps の中身を一つずつ見ていきましょう。

    Step 1: コードのチェックアウト

    1- uses: actions/checkout@v2
    2  with:
    3    ref: 'release'

    actions/checkout は、リポジトリのソースコードをワークフローを実行している環境(Runner)にコピーするための公式アクションです。

    ここで重要なのが with: ref: 'release' の部分です。

    これは、release ブランチの最新のコードを取得することを意味しています。

    ブランチの指定ミスを防ぐために、どのブランチ上でワークフローを実行しても release ブランチ上でデプロイ処理を行うようにしています。

    Step 2: Java環境のセットアップ

    1- name: set up JDK 17
    2  uses: actions/setup-java@v2
    3  with:
    4    java-version: '17'
    5    distribution: 'temurin'
    6    cache: gradle

    Androidアプリをビルドするためには、適切なバージョンのJava Development Kit (JDK) が必要です。actions/setup-java アクションがその役割を担います。

    java-version: '17'このプロジェクトで必要とされているJDK 17を指定しています。
    distribution: 'temurin'JDKのディストリビューションとしてEclipse Temurinを指定しています。
    cache: gradleGradleの依存関係やビルドキャッシュを保存します。これにより次回以降のビルド時間を大幅に短縮できます。

    Step 3: gradlewへの実行権限付与

    1- name: Grant Permission gradlew
    2  run: chmod +x gradlew

    gradlew (Gradle Wrapper) は、Gradleを簡単に実行するためのスクリプトファイルです。

    しかし、CI環境によっては、このファイルにデフォルトで実行権限が付与されていない場合があります。

    chmod +x gradlew は、gradlew ファイルに実行権限 (+x) を与えるためのLinuxコマンドです。

    後のステップで ./gradlew コマンドを実行しようとした際に「Permission denied」エラーが発生してしまう可能性があるため必要になります。

    Step 4: google-services.json の生成

    1- name: Make google-services.json
    2  env:
    3    GOOGLE_SERVICE: ${{ secrets.GOOGLE_SERVICE_JSON }}
    4  run: echo $GOOGLE_SERVICE | base64 --decode --ignore-garbage > ./app/google-services.json

    Firebaseを利用するAndroidアプリには、app/google-services.json ファイルが必須です。

    このファイルにはFirebaseプロジェクトに接続するための重要な情報が含まれています。

    しかし、このような セキュリティ上機密情報を含むファイルを直接リポジトリにコミットするのは厳禁ですので、GitHub Secrets を通じて取得します。

    env: GOOGLE_SERVICE: ${{ secrets.GOOGLE_SERVICE_JSON }}あらかじめリポジトリの「Settings > Secrets and variables > Actions」で登録しておいた google-services.json の内容を、secrets.GOOGLE_SERVICE_JSONを安全に呼び出し GOOGLE_SERVICE という環境変数にセットします。
    (JSONのままでは改行の問題で上手く取り扱えないため、 Base64 形式という1行の文字列にエンコードして登録しておきます)
    run: echo $GOOGLE_SERVICE | base64 --decode ...環境変数 GOOGLE_SERVICE にセットされたBase64文字列を base64 --decode で元のJSON形式にデコードし、./app/google-services.json でファイルとして書き出します。

    これにより、機密情報を安全に管理しつつ、ワークフロー内で必要なファイルを動的に生成することができます。

    Step 5: バージョンアップの実行

    1- name: Bump Patch Version
    2  run: ./gradlew bumpPatchVersion

    run: ./gradlew bumpPatchVersion は、前回の記事で作成したカスタムGradleタスクを実行しています。

    このコマンドが実行されると、app/build.gradle.kts 内に定義されたロジックが走り、versionCode が1つインクリメントされ、versionName のパッチ部分が1つインクリメントされた上で、app/build.gradle.kts ファイル自体が書き換えられます。

    Step 6: バージョン情報の取得

    1- name: Get Version
    2  run: |
    3    echo "::set-output name=VERSION_CODE::$(./gradlew -q printVersionCode)"
    4    echo "::set-output name=VERSION_NAME::$(./gradlew -q printVersionName)"
    5  id: version

    更新後のバージョン情報を、後のステップで再利用したい場合があります(例. プルリクエストのタイトル等)。

    そのため、環境変数にこちらを保存しておき、再利用できるようにしておきます。

    id: versionこのステップに version というIDを付与します。
    echo "::set-output name=..."これはGitHub Actionsの特殊な構文で、name で指定した名前(VERSION_CODEVERSION_NAME)で、echo した内容を出力変数として設定します。

    このステップが完了すると、後のステップで steps.version.outputs.VERSION_CODEsteps.version.outputs.VERSION_NAME のようにして、更新後のバージョン情報を参照できるようになります。

    Step 7: リリースAPKのビルド

    1- name: Building Release APK
    2  env:
    3    ENV_SIGN_KEYSTORE_BASE64: ${{ secrets.ENV_SIGN_KEYSTORE_BASE64 }}
    4    ENV_SIGN_KEY_ALIAS: ${{ secrets.ENV_SIGN_KEY_ALIAS }}
    5    ENV_SIGN_KEY_PASSWORD: ${{ secrets.ENV_SIGN_KEY_PASSWORD }}
    6    ENV_SIGN_STORE_PASSWORD: ${{ secrets.ENV_SIGN_STORE_PASSWORD }}
    7  run: ./gradlew assembleRelease

    次はいよいよこの更新後のバージョン情報で、いよいよアプリをビルドしてリリース用のAPKを作成していきます。

    ./gradlew assembleRelease がそのためのコマンドです。

    しかし、Google Play StoreやApp DistributionにアップロードするAPKファイルには、デジタル署名が必須です。

    この署名によって、アプリの作者が誰であるか、そしてアプリが改ざんされていないことを保証します。

    署名にはキーストアファイル(.jks)と、それに関連するパスワードやエイリアスが必要です。

    これらも google-services.json と同様に非常に重要な機密情報なので、GitHub Secretsを使って安全に取り扱っていきます。

    env: ...ブロックで署名に必要な情報をすべて環境変数として設定しています。

    ENV_SIGN_KEYSTORE_BASE64キーストアファイル(.jks)をBase64エンコードしてSecretsに保存したもの。
    ENV_SIGN_KEY_ALIASキーストアのエイリアス名。
    ENV_SIGN_KEY_PASSWORDキーのパスワード。
    ENV_SIGN_STORE_PASSWORDストアのパスワード。

    これらの環境変数は、app/build.gradle.ktssigningConfigs ブロックで読み込まれ、ビルド時に使用されます。

    1signingConfigs {
    2    create(releaseSigningConfigName) {
    3        val releaseKeystoreFileName = "release-keystore.jks"
    4        // 環境変数にキーストアのBase64文字列があればデコードしてファイルを作成
    5        if (System.getenv("ENV_SIGN_KEYSTORE_BASE64") != null) {
    6            System.getenv("ENV_SIGN_KEYSTORE_BASE64").let { base64 ->
    7                val decoder = Base64.getMimeDecoder()
    8                File(releaseKeystoreFileName).also { file ->
    9                    file.createNewFile()
    10                    file.writeBytes(decoder.decode(base64))
    11                }
    12            }
    13        }
    14        // 環境変数から署名情報を読み込む
    15        storeFile = rootProject.file(releaseKeystoreFileName)
    16        storePassword = System.getenv("ENV_SIGN_STORE_PASSWORD")
    17        keyAlias = System.getenv("ENV_SIGN_KEY_ALIAS")
    18        keyPassword = System.getenv("ENV_SIGN_KEY_PASSWORD")
    19    }
    20}

    このように、ワークフローとビルドスクリプトが連携することで、安全かつ自動的に署名付きAPKをビルドすることができます。

    Step 8: Firebase App Distributionへのデプロイ

    1- name: Deploy to App Distribution
    2  uses: wzieba/Firebase-Distribution-Github-Action@v1
    3  with:
    4    appId: ${{ secrets.FIREBASE_APP_ID }}
    5    serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}
    6    groups: release
    7    releaseNotesFile: RELEASE_NOTE.md
    8    file: ./app/build/outputs/apk/release/app-release.apk

    最後にビルドしたAPKをFirebase App Distributionにデプロイしていきます。

    ここでは wzieba/Firebase-Distribution-Github-Action というサードパーティ製のアクションを利用しています。

    これを利用することで、複雑なAPIコールなどを意識することなく、簡単な設定だけでデプロイを行うことが可能です。

    with 以下のパラメータを詳しく見ていきます。

    appId: ${{ secrets.FIREBASE_APP_ID }}デプロイ対象となるFirebaseアプリのID。Firebaseプロジェクトの設定画面から確認でき、これもSecretsで管理します。
    serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}GitHub ActionsからFirebaseを操作するための認証情報(サービスアカウントの秘密鍵)。FirebaseコンソールからJSON形式でダウンロードし、その内容をSecretsに保存します。(ファイルそのものではなく、中身のテキストを保存する点に注意)
    groups: releaseApp Distributionにおける配布対象のテスターグループを指定。ここでは release という名前のグループに配布しています。
    releaseNotesFile: RELEASE_NOTE.md配布時に表示されるリリースノートの内容をリポジトリ内の RELEASE_NOTE.md ファイルから読み込んで設定します。
    file: ./app/build/outputs/apk/release/app-release.apkアップロードするAPKファイルのパスを指定します。./gradlew assembleRelease で生成されるファイルの出力先をここに指定しておきます。

    このステップが成功すれば、指定したテスターグループに新しいバージョンのアプリの配信が通知されます。

    Step 9: リリースノートの初期化

    1- name: Init RELEASE_NOTE.md
    2  run: cat RELEASE_NOTE.init.md > RELEASE_NOTE.md

    デプロイが無事に完了したら、次のリリースのために少し後片付けをします。RELEASE_NOTE.md には今回のリリース内容が書かれていますが、このままだと次回のリリースでも同じ内容が使われてしまいます。

    そこで、cat RELEASE_NOTE.init.md > RELEASE_NOTE.md コマンドを実行します。

    RELEASE_NOTE.init.md は「定型文だけが書かれたテンプレートファイル」で、catコマンドでその内容を読み込み、RELEASE_NOTE.md に上書きしています。

    これにより、リリースノート用のファイルを手動でデフォルトに戻す作業を省略することができます。

    Step 10: 後処理のプルリクエスト作成

    1- name: Create Pull Request
    2  uses: peter-evans/create-pull-request@v6
    3  with:
    4    token: ${{ secrets.GITHUB_TOKEN }}
    5    branch: after-released-${{ steps.version.outputs.VERSION_NAME }}-${{ steps.version.outputs.VERSION_NAME }}
    6    base: release
    7    title: "Released version: `${{ steps.version.outputs.VERSION_NAME }}` / `${{ steps.version.outputs.VERSION_CODE }}`"
    8    commit-message: "Released version: `${{ steps.version.outputs.VERSION_NAME }}` / `${{ steps.version.outputs.VERSION_CODE }}`"

    このワークフロー実行による変更(build.gradle.kts のバージョンアップと RELEASE_NOTE.md の初期化)をマージするためのプルリクエストを作成します。

    ここでは peter-evans/create-pull-request というサードパーティ製のカスタムアクションを活用します。

    token: ${{ secrets.GITHUB_TOKEN }}アクションがリポジトリを操作(ブランチ作成やPR作成)するために必要なトークン。(GitHub側が自動的に付与)。
    branch: after-released-...プルリクエストの元となる新しいブランチの名前を指定します。steps.version.outputs.VERSION_NAME を使うことで、リリースしたバージョンがブランチ名から分かるようにしています。
    base: releaserelease ブランチに対してプルリクエストを作成します。
    title: "Released version: ..."プルリクエストのタイトル。ここでも steps.version.outputs を活用して、どのバージョンがリリースされたのか一目で分かるようにしています。
    commit-message: "Released version: ..."コミットメッセージ。こちらもプルリクエストのタイトルと同名にしておきます。

    このプルリクエストを release ブランチにマージすることで、一連のデプロイ作業が完了し、その履歴がGit上に綺麗に残ることになります。

    最後にこのreleaseブランチを、メインブランチや開発用のブランチにマージし、変更を反映するようにしましょう。

    これで作業は全て完了です!

    さいごに

    今回は、GitHub Actionsを使ってAndroidアプリの「バージョンアップ → ビルド → 署名 → Firebase App Distributionにデプロイ → 後処理」という一連の流れを、ボタン一つで完結させるワークフローを解説していきました。

    自分が自動化大好き人間 + 面倒くさがり屋なので、この部分を自動化できたのはとても大きかったですね(笑)

    個人開発で利用しているのですが、手作業で行うと10〜15分程かかる内容を2〜3分で完了できるようになりましたし、ヒューマンエラーもなくなるので、デプロイ作業がぐっと楽になり保守性も上がりました。

    AndroidアプリはLinux環境でビルドできますし、リポジトリをPublicにしておけば、無料でこの自動化ワークフローを走らせることができるので、敷居が低く個人開発にも取り入れやすいのもメリットの大きな一つに感じています。(機密情報の漏洩には気をつける必要がありますが)

    チーム開発を行う際でも、このような自動化・効率化を行うことでチーム全体の生産性を飛躍的に向上させることができます。

    デフォルト環境でも比較的軽量に動くワークフローなので、もし興味があればご自身のリポジトリで体験してもらえるとめちゃめちゃ嬉しいです!

    あなたの開発体験の底上げに少しでもお役に立てていれば幸いです!

    最後までお読みいただき、ありがとうございました!

    それではまた!

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    こー(エンジニア)
    こー(エンジニア)
    Show more...

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background