時間の浪費を止めよう:FastlaneとGitHub Actionsでモバイルリリースを自動化する

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

手動によるモバイルデプロイの大きなコスト

手動でのデプロイは生産性を著しく低下させます。モバイル開発者なら誰でも経験があるはずです。機能を完成させた後、次の1時間を.ipaや.apkファイルの生成に費やします。ビルドが途中で失敗しないことを祈りながら、プロビジョニングプロファイルを慎重に操作します。私自身、以前はXcodeやGoogle Play Consoleの監視だけで、リリース週に少なくとも4〜6時間を失っていました。

自動化されたCI/CDパイプラインに切り替えたことで、ワークフロー全体が変わりました。進捗バーを眺める代わりに、チームは機能の開発に集中できるようになり、重労働はマシンが担当するようになりました。私たちはビルドロジックの実行にFastlaneを、クラウドインフラの提供にGitHub Actionsを使用しています。このセットアップにより、すべてのビルドがクリーンで、正しく署名され、人の手を介さずにテスターに届けられるようになります。

環境のセットアップ

自動化を始める前に、ローカルでFastlaneを実行できる状態にする必要があります。FastlaneはRubyベースであるため、Ruby環境が必要です。macOSにはRubyが含まれていますが、rbenvasdfの使用をお勧めします。これらのマネージャーを使用することで、システム標準のRubyバージョンでよく発生する権限の問題を回避できます。

1. Bundler経由でFastlaneをインストールする

Fastlaneをグローバルなgemとしてインストールするのは避けましょう。代わりに、プロジェクトのルートにあるGemfileを使用して、チーム全員が同じバージョンを使用するようにします。以下のコマンドを実行して開始します:

gem install bundler
echo 'source "https://rubygems.org"
gem "fastlane"' > Gemfile
bundle install

次に、プロジェクトフォルダ(.xcodeprojbuild.gradleがある場所)でFastlaneを初期化します:

bundle exec fastlane init

Fastlaneはいくつかのセットアップオプションを提示します。iOSの場合、通常はスクリーンショットの自動化、TestFlight、または完全なApp Store配信のいずれかを選択します。Androidの場合、パッケージ名とGoogle Play ConsoleからのJSON秘密鍵が必要になります。完了すると、Fastlaneはfastlaneフォルダの中にFastfileを作成します。

2. GitHub Actionsの構造を準備する

GitHub Actionsは別途インストールする必要はありません。リポジトリ内に直接配置されます。自動化スクリプトを配置するディレクトリを作成するだけです:

mkdir -p .github/workflows

自動化ロジックの記述

Fastfileは、手動でのクリック操作をコードに変換する場所です。「lane(レーン)」を定義します。これは本質的に、ベータテストや本番リリースなどの特定のタスクのためのスクリプトです。

Fastfileのレーンを定義する

レーンは、繰り返し利用可能なレシピのようなものだと考えてください。以下は、証明書の処理、アプリのビルド、TestFlightへのプッシュを行うiOSベータ用レーンの実践的な例です:

platform :ios do
  desc "TestFlightに新しいベータビルドをプッシュ"
  lane :beta do
    setup_ci
    match(type: "appstore") # 証明書を同期
    increment_build_number(build_number: ENV["GITHUB_RUN_NUMBER"])
    build_app(scheme: "YourAppName")
    upload_to_testflight
  end
end

Androidの場合も、プロセスは同様にシンプルです。このレーンは本番環境用のApp Bundleを生成し、内部テストトラックに送信します:

platform :android do
  desc "Google Play内部テストトラックに新しいビルドを送信"
  lane :beta do
    gradle(task: "bundle", build_type: "Release")
    upload_to_play_store(track: "internal")
  end
end

コード署名の悪夢を解決する

iOSのコード署名は、CIサーバー上では非常に困難なことで知られています。キーチェーンのプロンプトで手動で「許可」をクリックできないためです。Fastlane Matchは、証明書を暗号化されたプライベートなGitリポジトリに保存することで、この問題を解決します。このアプローチにより、チーム全体で唯一の真実のソース(Source of Truth)を共有できます。fastlane match initを実行してセットアップしてください。これにより、CIランナーが常にアプリの署名に必要な正確な認証情報を保持できるようになります。

GitHub Actionsワークフローの設定

.github/workflows/deploy.ymlファイルを作成します。このスクリプトは、mainブランチにコードがプッシュされるたびにFastlaneのレーンをトリガーするようGitHubに指示します。

name: ベータ版へのデプロイ
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.1'
          bundler-cache: true
      - name: Fastlaneを実行
        env:
          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
          APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
        run: bundle exec fastlane ios beta

重要なヒント:パスワードを決してハードコードしないでください。MATCH_PASSWORDのような機密性の高い値は、GitHubのSettings > Secretsに保存してください。これにより、ビルドランナーがアクセスできるようにしつつ、認証情報を安全に保つことができます。

監視と最適化

この設定をプッシュすると、GitHubの「Actions」タブでビルドの進捗をリアルタイムで確認できるようになります。ビルドが失敗した場合、通常Fastlaneは明確なエラーテーブルを表示します。APIキーの権限が不足している場合は「Error 403」、ビルド番号のインクリメントを忘れた場合は「Version Conflict」などが表示されることがあります。

ビルド時間に注意する

GitHubのmacos-latestランナーでのiOSビルドには、15分から30分程度かかることを想定してください。macOSランナーはLinuxランナーよりも大幅に高価(多くの場合、1分あたりのコストが10倍以上)であるため、トリガーを最適化しましょう。小さなコミットごとに完全なデプロイを実行するのは避け、プルリクエストがマージされたときや特定のタグが作成されたときにのみビルドをトリガーするようにします。

チームへの通知

最後に、FastfileにSlack通知を追加することをお勧めします。slackアクションを使用して、ビルドの成功または失敗時にチームのチャンネルにメッセージを投稿します。これにより、全員がGitHubのログを手動で確認することなく、最新の状態を把握できます。このシステムが稼働し始めると、デプロイにどれほど多くの精神的エネルギーを浪費していたかに気づくでしょう。

after_all do |lane|
  slack(message: "バージョン #{get_build_number} を TestFlight に正常にデプロイしました!")
end
Share: