Github ActionでFlutterアプリをTestFlight配信する

本記事ではGithub ActionでFlutterアプリをTestFlight配信する方法を紹介します（対象OSはiOSのみとなります）。

# 方法

Github Action内でfastlaneの各種コマンドを実行します。
このために

- Fastfile
- Github Actionの実行ファイル

を設定する必要があります。

# 事前準備

1. [fatlane match](https://docs.fastlane.tools/actions/match/)で証明書を管理している
    - 本記事ではGithub Action上で証明書使う手法として、matchによって証明書等が管理されているリポジトリから証明書等をダウンロードする方法を取っています。
1. Githubの[Fine-grained personal access tokens](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#fine-grained-personal-access-token-1)を発行している
    - 1のmatchで作成されたリポジトリをcloneする際に必要になります。[personal access tokens (classic)](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#personal-access-token-%E3%81%AE%E7%A8%AE%E9%A1%9E)でも可能ですが、Fine-grained personal access tokensの使用が推奨されています。
    - [Deploy Key](https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/managing-deploy-keys)を使う事も可能です。
1. [App Store Connect API](https://developer.apple.com/jp/help/app-store-connect/get-started/app-store-connect-api/)のキーを発行している
    - TestFlightにアップロードする際にこのキーが必要になります。

# 設定ファイル


## Fastfile

```ruby:Fastfile

default_platform(:ios)

platform :ios do

  def update_build_number
    increment_build_number(
      skip_info_plist: true,
      build_number: number_of_commits)
  end

  lane :upload_testflight do
    access_token = ENV['PERSONAL_ACCESS_TOKEN']

    # 1. 証明書のインストール
    match(
      git_url: "https://#{YOUR_NAME}:#{access_token}@github.com/#{YOUR_NAME}/#{YOUR_REPOSITORY_NAME}.git",
      type: "appstore",
      app_identifier: "YOUR_APP_IDENTIFIER",
      readonly: true)

    # ビルド番号はコミット数とする
    update_build_number

    update_code_signing_settings(
      use_automatic_signing: false,
      path: "Runner.xcodeproj",
      profile_name: "YOUR_PROFILE_NAME",
      code_sign_identity: "YOUR_CODE_SIGN_IDENTITY"
    )

    build_app(
      output_name: 'IPA_NAME',
      output_directory: 'build/ios/',
    )

    # 2. App Store Connect APIの API Keyを取得
    api_key = app_store_connect_api_key(
      key_id: ENV['ASC_KEY_ID'],
      issuer_id: ENV['ASC_ISSUER_ID'],
      key_content: ENV['ASC_KEY_CONTENT'],
    )

    upload_to_testflight(
      api_key: api_key,
      skip_waiting_for_build_processing: true,
      ipa: 'IPA_NAME'
    )
  end
end


```

### 1. 証明書のインストール

[match](https://docs.fastlane.tools/actions/match/#match)を使用して証明書のインストールを行います。`git_url`の設定は[Stack OverFlowのこちらの解答](https://stackoverflow.com/questions/42148841/github-clone-with-oauth-access-token/66156992#66156992)を参考にしています。`Fine-grained personal access tokens`を使用する際はこういった指定をする必要があるようです。


### 2. App Store Connect APIの API Keyを取得

App Store Connect APIの API Keyを使う事で2段階認証が必要なくなるといったメリットがあります。
https://docs.fastlane.tools/app-store-connect-api/


## Github Actionのファイル

```yaml:Github Actionのファイル
name: upload_testflight

on:
  push:
    branches: [feature/xxx]

jobs:
  build:
    runs-on: macos-12
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      # 1. Flutter SDKのインストール
      - name: install flutter
        uses: subosito/flutter-action@v2
        with:
          flutter-version: "3.10.6"
          channel: "stable"
          cache: true

      - name: flutter dependencies install
        run: flutter pub get

      # 2. CocoaPodsを使用したライブラリのインストール
      - name: Pod cache
        uses: actions/cache@v3
        id: cache-cocoapods
        with:
          path: ios/Pods
          key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-pods-

      - name: Pod Install
        if: steps.cache-cocoapods.outputs.cache-hit != 'true'
        run: |
          cd ios/
          pod install

      - name: Upload testflight
        run: |
          cd ios
          fastlane upload_testflight
        env:
          PERSONAL_ACCESS_TOKEN: ${{secrets.PERSONAL_ACCESS_TOKEN}}
          ASC_KEY_ID: ${{secrets.ASC_KEY_ID}}
          ASC_ISSUER_ID: ${{secrets.ASC_ISSUER_ID}}
          ASC_KEY_CONTENT: ${{secrets.ASC_KEY_CONTENT}}
          MATCH_PASSWORD: ${{secrets.MATCH_PASSWORD}}



```

## 1. Flutter SDKのインストール

`cache: true`を設定する事でSDKをキャッシュする事ができます。これによりCIの実行時間短縮が見込めます。

## 2. CocoaPodsを使用したライブラリのインストール

こちら1と同様にキャッシュをしています。

# 参考
- https://docs.github.com/ja/actions
- https://docs.fastlane.tools/
- https://zenn.dev/himara2/articles/6a46c977567615
- https://qiita.com/SUGYKEN/items/b654eb65478e51554936#pod%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E4%BB%A5%E4%B8%8B%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E7%99%BA%E7%94%9F%E3%81%97%E3%81%9F%E3%81%9F%E3%82%81pod-install%E3%81%AEjob%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%A6%E8%A7%A3%E6%B1%BA%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F
- https://stackoverflow.com/questions/42148841/github-clone-with-oauth-access-token/66156992#66156992