🎂

【Flutter】個人アプリにGitHub ActionsでCI/CDを導入してみる

2025/03/04に公開

個人で開発しているアプリのテストやデプロイを自動化したいと思い、CI/CDを導入することにしました。今回はGitHub Actionsを使って、テスト、リントチェック、APKのアップロードまでを目標としたCI/CDの設定方法の手順を書いていこうと思います。

CI/CDとは

CI(継続的インテグレーション)とCD(継続的デリバリー)は、ソフトウェア開発のプロセスを効率化するための手法です。

CI (Continuous Integration): インテグレーション(integration)は、複数のものを組み合わせてまとめることを意味します。開発者がコードをリモートリポジトリに頻繁に統合することで、コードのバージョン管理やテストの自動化を行います。これにより、コードの品質を保ちながら、チームメンバー全員が同じコードベースで作業できます。

CD (Continuous Deployment/Continuous Delivery): デリバリー(Delivery)は、ソフトウェアが「配信可能な状態」であることを意味します。CDは、CIの結果として得られたコードを自動でデプロイする仕組みです。Continuous Deliveryは、ビルドされたコードが手動でデプロイ可能な状態に保たれることを意味し、Continuous Deploymentは、そのコードが自動で本番環境にデプロイされることを意味します。

CI/CDを導入することで、テストやビルドのプロセスを自動化でき、手動でのエラーを減らし、素早く安定したリリースができるようになります。

GitHub Actionsとは

GitHub Actionsは、GitHubが提供するCI/CDツールで、リポジトリに直接統合されており、コードのビルド、テスト、デプロイを自動化できます。GitHub Actionsは、コードの変更がリポジトリにプッシュされたタイミングで自動的にワークフローを実行することができ、これによりCI/CDを実現できます。
GitHub Actionsは、YAML形式でワークフローを定義し、特定のトリガー(例えば、プッシュやプルリクエスト)によって実行されるジョブ(タスクの単位)を設定します。
個人開発をしているリポジトリはパブリックのため、無制限にGithub Actionを使用できるようでした。 プライベートリポジトリでは、GitHubのプランに応じて、無料枠として使用できる時間やストレージが付与され、これを超えると、追加料金が発生するようです。

詳しくはこちらの記事を参考にしました。
https://docs.github.com/ja/billing/managing-billing-for-your-products/managing-billing-for-github-actions/about-billing-for-github-actions

設定方法

GitHub ActionsでCI/CDを実現するためには、まずリポジトリ内にワークフローの設定ファイルを作成する必要があります。以下にその手順を説明します。

1. GitHubリポジトリを準備する

GitHubにアプリのリポジトリを作成します。すでにリポジトリがある場合は、そちらを使用します。

2. GitHub Actions用の設定ファイルを作成する

リポジトリ内に.github/workflows/ディレクトリを作成し、その中にワークフローファイル(flutter.yml)を作成します。そしてflutter.ymlに設定を書いていきます。
mainブランチへのpush時または、mainブランチへのPR作成時にGithub Action上でワークフロー内のジョブが実行されます。

name: Flutter CI

  # ワークフローをトリガーするイベントを定義
on:
  push:
    branches:
      - main  # mainブランチへのpush時に実行
  pull_request:
    branches:
      - main  # mainブランチへのPR作成時に実行

# ワークフロー内のジョブを定義
jobs:
  build:
    # ジョブが実行される仮想環境を指定
    runs-on: ubuntu-latest

    steps:
    # リポジトリのコードをチェックアウト
    - name: Checkout code
      uses: actions/checkout@v2
    
    # fvmのバージョンを取得
    - name: "Read flutter version from fvm config"
      id: flutter_info
      run: |
        FLUTTER_VERSION=$(jq -r '.flutterSdkVersion' ./.fvm/fvm_config.json)
        echo "FLUTTER_VERSION=$FLUTTER_VERSION" >> $GITHUB_ENV
      shell: bash

    # Flutterのセットアップ
    - name: "Setup Flutter"
      uses: subosito/flutter-action@v2
      with:
        flutter-version: ${{ env.FLUTTER_VERSION }}  # 取得したFlutterバージョンを使用
        cache: true

    # flutter cleanを実行してキャッシュを削除
    - name: Clean Flutter build
      run: flutter clean

    # Flutterの依存関係をインストール
    - name: Install dependencies
      run: flutter pub get

    # リモートリポジトリでGitHub Secretsから.envファイルを動的に作成
    - name: Create .env
      run: echo "GEMINI_API_KEY=${{ secrets.GEMINI_API_KEY }}" >> .env

    # リントチェックを実行
    - name: Run linter
      run: flutter analyze

    # テストを実行
    - name: Run tests
      run: flutter test

    # Androidのkeystoreファイル(key.jks)をSecretsからデコードして配置
    - name: Decode keystore
      run: echo "${{ secrets.SIGNING_KEY }}" | base64 -d > android/app/key.jks

    # Androidのビルド(Secretsから署名情報を取得)
    - name: Build APK (Android)
      run: flutter build apk --release
      env:
        KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }}
        KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
        ALIAS: ${{ secrets.ALIAS }}
        KEY_PATH: key.jks

    # ビルドしたapkをgithub Actionsアップロード
    - name: "Deploy apk 🚀"
      uses: actions/upload-artifact@v4
      with:
        name: release-apk  # アーティファクトの名前
        path: build/app/outputs/flutter-apk/app-release.apk
        retention-days: 7 # 7日間保存

ここで、.envファイルがリモートリポジトリにないことで、リントチェックでコケてしまうエラーがでました。少しハマったのですが、GitHub Secretsを使用してリモートリポジトリで.envファイルを動的に作成されるようにしたら解決しました。ありがとうございます!!
https://blog.shinonome.io/githubactions/

また、Androidのリリースビルド時のSignも、GitHub Secretsを使用して安全にAPKをアップロードするようにしています。

3. GitHub Actionsを有効化する

flutter.ymlをリポジトリにコミットした後、GitHubの「Actions」タブに移動し、CI/CDが正しく動作するかを確認します。コードをmainブランチにプッシュか、PRを作成すると、GitHub Actionsが自動的にトリガーされ、定義したタスク(ビルドやテスト)が実行されます。

.envファイルがリモートリポジトリにないことで、リントチェックでコケてしまう問題で、少しハマりそうになりましたが、目標までは完成することができました!
今後はiOS側のTestFlightを自動でアップロードできるようにしていきたいです。

※2025/3/21追記
後日Xcode CloudでTestFlightに自動デプロイするようにしました!
これはスクラップで記録してますので、ご参考程度になれば幸いです。
https://zenn.dev/tarakosuziko/scraps/f25006ce43963b

参考

https://zenn.dev/imajoriri/articles/c25b40bec11fa6
https://qiita.com/freddiefujiwara/items/76cfc05f5142d3b53da6#apkをgithub-actionsを使ってsignする

Discussion