👾

【2025年最新版】Flutter × GitHub Actions × FastlaneでAndroidの内部テスト配布を自動化(CD)

に公開

自動化したこと

developブランチにプッシュしたタイミングでAndroidの内部テスト配布をした

注意点

今回の自動化をする上で以下の注意点があるので、もし自動化したい場合はまずはテスト配布できるようにしてからカスタマイズすることをオススメします。(動くものができてから)

  1. リリースノートは作成されません。
  2. 製品版やクローズドテストは、内部テスト配布したバージョンをGooglePlayConsoleからプロモートする必要がある

前提条件

  1. flutter runしてAndroid端末でアプリを起動できる
  2. GooglePlayConsoleでテスト配布するアプリを作成済み
  3. GoogleCloudPlatformでテスト配布するアプリのプロジェクトを作成済み
  4. Rubyのインストール(fastlaneを実行するために必要)

実装する手順

以下の9つの手順で動くようになります(全体感)

  1. Fastlaneのインストール
  2. GooglePlayConsoleとGoogleCloudPlatformの設定
  3. Androidプロジェクトの設定
  4. fastlaneの初期化
  5. Github Secretsの設定
  6. fastlane関連ファイルの設定
  7. 手動での初回リリース(内部テスト配布済みなら飛ばしてOK)
  8. Github Actionsの実装
  9. いざGithub Actionsを実行!

Fastlaneのインストール

HomeDirで以下を実行する

sudo gem install fastlane -NV

fastlaneをgemを使用してインストールしています。(brewでも問題ありません)
※ 開発環境によっては brew install fastlane の方が依存関係が少なく済むケースもあります。

GoogleCloudPlatformの設定


サービスアカウントの作成

Fastlane などのツールが Google Play Developer API を使ってビルドをアップロードするには、OAuth 2.0 認証が必要です。そのためにサービスアカウントが使われます。

  1. IAMと管理ページに移動
  2. サービスアカウントに移動
  3. サービスアカウントを作成する
    4. アカウント名などは自由に入力してください
    5. ロールは「オーナー」を選択(私の場合はオーナーを選択しましたが別のロールでも問題ない)
  4. サービスアカウントページのリストに先ほど入力したサービスアカウントが表示されていることを確認してステータスが「有効」になっていること

サービスアカウントの秘密鍵を作成

Google Play Android Developer APIを使ってビルドやメタデータを自動アップロードする際に、認証(アクセス権)を与えるためにこの鍵が必要になります。

  1. 「キーを追加」を押す
  2. 「新しい鍵を作成」を押す
  3. 秘密鍵の作成は「JSON」を選択する
  4. ローカルに保存する(保存したパスを忘れないようにしてください)

Google Play Android Developer APIを有効

fastlaneが自動でビルドしたファイルをGooglePlayConsoleにアップロードするために必要になります


「☑️ API が有効です」と表示されればOKです

GooglePlayConsoleの設定

  1. サービスアカウントの作成で作成したメールを指定する
  2. テスト自動化するアプリを選択してユーザーを招待する

Androidプロジェクトの設定

Androidのリリースには .aab ファイルのアップロードが必要です。.aab ファイルを生成するためにビルドを行いますが、そのビルドを成功させるために必要な設定です

この設定を既に実装済みの場合はこのステップを飛ばしてください

まだ実装してない方は、以下の記事より設定を行う必要があります

https://zenn.dev/wakanao/scraps/dcf40befa3d7c2

上記記事で設定が完了したらflutter build appbundle --releaseのビルドが成功するかをチェックしてください(成功したらOK)

fastlaneの初期化

fastlaneを実行する上で必要です

cd your_flutter_project/android
fastlane init

自動テスト配布するアプリのパッケージ名を入力する

Package Name (com.krausefx.app):

サービスアカウントの秘密鍵を作成で作成した時に保存したローカルパスを入力する

入力するときには、ローカルに秘密鍵(jsonファイル)を保存した絶対パス(/Users/your-name/…)を指定する

Path to the json secret file:
  • y を選ぶと、アプリの説明やスクリーンショットなどを自動で管理できます。
  • 今回は n を選び、あとで fastlane supply init にて設定可能です。
Download existing metadata and setup metadata management? (y/n)
n

initが成功すると以下の2ファイルが作成されます

  1. android/fastlane/Appfile
  2. android/fastlane/Fastfile

Github Secretsの設定

関係者(または自分)以外の人にパスワードやAPIキーなどが漏洩しないようにするために使用する(セキュリティ観点)

設定方法がわからない方は以下のドキュメントを参考にしてください
https://docs.github.com/ja/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions

以下の5つの設定が必要です

  1. PLAY_CONFIG_JSON:Google Play JSONキーファイルのBase64エンコード
  2. ANDROID_KEYSTORE_FILE: KeystoreファイルのBase64エンコードしたコード
  3. KEYSTORE_STORE_PASSWORD: Keystoreファイルのパスワード
  4. KEYSTORE_KEY_ALIAS: Keystoreファイルののエイリアス
  5. KEYSTORE_KEY_PASSWORD: Keystoreファイルのパスワード

PLAY_CONFIG_JSON:Google Play JSONキーファイルのBase64エンコード

cd [サービスアカウントの秘密鍵を作成]で保存したdirに移動
base64 -i upload-keystore.jks
  1. base64コマンドを叩いて表示されたbase64コードをコピーします。
  2. Github SecretsでPLAY_CONFIG_JSONのvalueにコピーしたコードをペーストして設定する

ANDROID_KEYSTORE_FILE:KeystoreファイルのBase64エンコード

cd [Androidプロジェクトの設定]で保存したdirに移動(おそらくandroi/app/にある)
base64 -i xxx.jks
  1. base64コマンドを叩いて表示されたbase64コードをコピーします。
  2. Github SecretsでANDROID_KEYSTORE_FILEのvalueにコピーしたコードをペーストして設定する

  • KEYSTORE_STORE_PASSWORD: Keystoreファイルのパスワード
  • KEYSTORE_KEY_ALIAS: Keystoreファイルのエイリアス
  • KEYSTORE_KEY_PASSWORD: Keystoreファイルのパスワード

これらは、.propertiesファイルに記載されている情報を元にGithub Secretsにそれぞれ設定してください

fastlane関連ファイルの設定

以下のコードをコピペしてお使いください
package_nameは変更する必要があります

android/fastlane/Appfile
json_key_file(ENV['ANDROID_JSON_KEY_PATH'])
package_name("com.example.applicationId")

AppfileはFastlaneが使うテスト配布を自動化するアプリの認証情報を定義するファイルです


android/fastlane/Fastlane
default_platform(:android)

platform :android do
  desc "Runs all the tests"
  lane :test do
    gradle(task: "test")
  end

  desc "Submit a new Beta Build to Crashlytics Beta"
  lane :beta do
    gradle(task: "clean assembleRelease")
    crashlytics
  end

  desc "Deploy a new version to the Google Play"
  lane :deploy do
    gradle(task: "clean assembleRelease")
    upload_to_play_store
  end

  desc "内部テスト用のビルドとGoogle Playへのアップロード"
  lane :internal do
    current_branch = `git rev-parse --abbrev-ref HEAD`.strip
    if !["main", "develop"].include?(current_branch)
      UI.user_error!("このレーンはmainかdevelopブランチからのみ実行できます")
    end
    

    previous_build_number = google_play_track_version_codes(track: "internal")[0]
    new_version_code = previous_build_number + 1

    sh("cd .. && flutter clean")
    sh("cd .. && flutter pub get")
    sh("cd .. && flutter build appbundle --build-number=#{new_version_code}")

    upload_to_play_store(
      track: 'internal',
      aab: "../build/app/outputs/bundle/release/app-release.aab",
      skip_upload_apk: true,
      skip_upload_metadata: true,
      skip_upload_images: true,
      skip_upload_screenshots: true
    )
  end
end

このファイルで定義したコマンドを実行すると内部テスト配布をCLIから実行してくれる

Github Actionsの実装

以下のコードをコピペしてお使いください

.github/workflows/android-cd
name: Android内部テスト配信

on:
  push:
    branches: [ develop ]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Javaのセットアップ
        uses: actions/setup-java@v3
        with:
          distribution: 'zulu'
          java-version: '17'
      
      - name: Flutterのセットアップ
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.x'
          channel: 'stable'
      
      - name: Flutterパッケージの取得
        run: flutter pub get

      - name: Restore .env file # 任意
        run: echo "${{ secrets.ENV_FILE }}" > .env
      
      - name: シークレット値のマスク
        run: |
          echo "::add-mask::${{ secrets.ANDROID_KEYSTORE_FILE }}"
          echo "::add-mask::${{ secrets.KEYSTORE_STORE_PASSWORD }}"
          echo "::add-mask::${{ secrets.KEYSTORE_KEY_PASSWORD }}"
          echo "::add-mask::${{ secrets.KEYSTORE_KEY_ALIAS }}"
          echo "::add-mask::${{ secrets.PLAY_CONFIG_JSON }}"
      
      - name: キーストアファイルの復元
        run: |
          cat <<EOF | base64 --decode > android/app/upload-keystore.jks
          ${{ secrets.ANDROID_KEYSTORE_FILE }}
          EOF
      
      - name: key.propertiesの作成
        run: |
          cat <<EOF > android/key.properties
          storePassword=${{ secrets.KEYSTORE_STORE_PASSWORD }}
          keyPassword=${{ secrets.KEYSTORE_KEY_PASSWORD }}
          keyAlias=${{ secrets.KEYSTORE_KEY_ALIAS }}
          storeFile=upload-keystore.jks
          EOF
      
      - name: Play Storeの認証ファイルを設定
        run: |
          cat <<EOF | base64 --decode > android/play-store-credentials.json
          ${{ secrets.PLAY_CONFIG_JSON }}
          EOF
      
      - name: Rubyのセットアップ
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.1'
          bundler-cache: true
      
      - name: fastlaneの実行
        run: |
          cd android
          bundle install
          bundle exec fastlane internal
        env:
          PLAY_CONFIG_JSON: ${{ secrets.PLAY_CONFIG_JSON }}
          ANDROID_JSON_KEY_PATH: play-store-credentials.json

      - name: Clean up .env # 任意
        run: rm .env

このyamlファイルをリモートリポジトリにプッシュすると任意のタイミングでGithub Actionsが実行されます

Restore .env fileClean up .envをしている箇所がありますが、これは任意になります。(削除しても良いコード)
私のFlutterプロジェクトでは.envファイルを使用しているため必要になります

※ そのためENV_FILEをGithub Secretsに設定してない場合は設定する必要があります

.envファイルに記載されているコードをそのままvalueに貼って問題ないです。(以下のように宣言されているコードをそのままvalueに貼ってください)

EXAMPLE_API_KEY=xxx
EXAMPLE_API_KEY2=xxx

今回はdevelopブランチにプッシュしたら実行されるコードになっているため、お好きにカスタマイズしてください

いざGithub Actionsを実行!

これらの設定をリモートリポジトリに反映させます。
そのあと、developブランチに向けてプッシュするとGithub Actionsが動いて自動で内部テスト配布してくれると思います!


まとめ

私自身のアウトプットを兼ねて作成した記事になります🙇
もし、手順通り進めたがうまく動かない等ありましたら教えていただけると幸いです!

Discussion