【Flutter】Github ActionでiOSアプリをDeployGateに自動デプロイする

Flutterで作ったアプリをiOS向けにクローズド配信する時に、せっかくなので自動化したいと思い、Github Actionsを使用してCI/CD環境を構築する方法をまとめました。
masterブランチにpushされた時に、自動でDeployGateにアップロードされるようになっています。

また、今回の方法はこちらの記事を参考にしました。

https://www.mum-meblog.com/entry/research-detail/flutter-ios-ci-cd

# 完成版
```yml:main.yml
name: iOS CI/CD

on:
  push:
    branches: [ master ]

jobs:
  build:
    runs-on: macos-latest

    steps:
      - uses: actions/checkout@v3

      - name: Select Xcode version 13.1
        run: sudo xcode-select -s '/Applications/Xcode_13.1.app/Contents/Developer'
      
      - name: Show Xcode version
        run: xcodebuild -version

      - name: setup cache      
        uses: actions/cache@v1
        with: 
          path: /Users/runner/hostedtoolcache/flutter
          key: ${{runner.OS}}-flutter-install-cache

      - name: install flutter      
        uses: subosito/flutter-action@v1
        with:
          flutter-version: '3.3.8'
          channel: 'stable'
          
      - name: flutter dependencies install
        run: flutter pub get

      - name: Import Provisioning Profile
        env:
          PROVISIONING_PROFILE: ${{ secrets.PROVISIONING_PROFILE }}
        run: |
          mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
          touch ~/Library/MobileDevice/Provisioning\ Profiles/decoded.mobileprovision
          echo -n $PROVISIONING_PROFILE | base64 -d -o ~/Library/MobileDevice/Provisioning\ Profiles/decoded.mobileprovision
          
      - name: Import Code-Signing Certificates
        uses: Apple-Actions/import-codesign-certs@v1
        with:
          p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
          p12-password: ${{ secrets.CERTIFICATE_PASSWORD }}
          
      - name: Import Export Options
        env:
          EXPORT_OPTIONS: ${{ secrets.EXPORT_OPTIONS }}
        run: echo -n $EXPORT_OPTIONS >> ExportOptions.plist
      
      - run: flutter build ipa --export-options-plist=ExportOptions.plist

      - name: Distribute iOS app
        env:
          DEPLOYGATE_API_KEY: ${{ secrets.DEPLOYGATE_API_KEY }}
          IOS_DISTRIBUTION_HASH: ${{ secrets.IOS_DISTRIBUTION_HASH }}
          DEPLOYGATE_USER: ${{ secrets.DEPLOYGATE_USER }}
        run: |
          curl \
            -H "Authorization: token $DEPLOYGATE_API_KEY" \
            -F "file=@/Users/runner/work/<アプリ名>/<アプリ名>/build/ios/ipa/<アプリ名>.ipa" \
            -F "message=git:$GIT_HASH" \
            -F "distribution_name=$GIT_BRANCH" \
            -F "release_note=new ios build" \
            -F "distribution_key=$IOS_DISTRIBUTION_HASH" \
            "https://deploygate.com/api/users/$DEPLOYGATE_USER/apps"
```

### Github Secretsの概要
|  名前                   |  内容  |
| ---------------------- | ---- |
|  PROVISIONING_PROFILE  |  mobileprovisionファイルをbase64でエンコードしたもの  |
|  CERTIFICATES_P12      |  p12ファイルをbase64でエンコードしたもの  |
|  CERTIFICATE_PASSWORD  |  p12ファイルに設定したパスワード  |
|  EXPORT_OPTIONS        |  ipaと一緒に出力されたExportOptions.plistファイル  |
|  DEPLOYGATE_API_KEY    |  DeployGateの アカウント設定 > APIKey に記載されているAPIキー  |
|  IOS_DISTRIBUTION_HASH |  DeployGateのアプリ配布ページURLに記載されているハッシュ値  |
|  DEPLOYGATE_USER       |  DeployGateのアカウントに登録したユーザ名  |

# Certificates と p12ファイル
Apple DeveloperのCertificatesタブから、Apple Distributionを選択し作成する方法と、Xcodeから作成する方法があります。

Apple Developerサイトから作成する場合、キーチェーンアクセスを使用して手動で登録する必要があるため、Xcodeを利用したほうが楽です。

やり方としては、XcodeのPreferenceから Manage Certificates... を選択しApple Distributionを作成するだけです。
![スクリーンショット 2021-12-10 0.02.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985195/eb475752-0321-f1cf-0d8b-b4d2c9d4c128.png)

その後、MacのキーチェーンアクセスからApple Distributionを選択しp12形式で書き出すことで完了です。
base64でエンコードしたp12ファイルと、書き出し時に使用したパスワードを、それぞれSecretsに登録してください。

https://zenn.dev/welchi/articles/xcode-revoke-certificate

キーチェーンアクセスからの出力に関してはこちらの記事が参考になります。

# Provisioning Profile
Apple DeveloperのProfilesタブから、Ad Hocを選択して新しいプロファイルを作成します。
![スクリーンショット 2021-12-09 23.46.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985195/fa379f85-256d-f956-b096-e4336d0cc2e9.png)

右上のDownloadからダウンロードしたmobileprovisionファイルをbase64でエンコードすると完了です。

# Export Options
Flutter 1.24.0-6.0 以降のバージョンから `flutter build ipa` でipaファイルが出力できるようになりました。
ExportOptions.plist を指定しないとアーカイブのみ出力されますので、こちらも用意します。

予めローカル環境にて `flutter build ipa` を行った後、Xcodeで Runner.xcarchive ファイルを開き、Ad hoc形式で出力するとipaファイルと同じフォルダ内に ExportOptions.plist も出力されています。

今回はそのままSecretsにそのまま貼り付けましたが、余力があれば必要な部分のみ隠すよう main.yml を変更すると尚良いです。
![スクリーンショット 2021-12-10 0.44.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985195/6c37cdc3-8fea-e50b-59f5-7d19f471ee57.png)

また、下記のようなエラーが発生する場合

`No profiles for <bundle id> were found: Xcode couldn't find any iOS App Development provisioning profiles matching <bundle id>. Automatic signing is disabled and unable to generate a profile.`

出力する前に、ReleaseタブのAutomatically manage signingのチェックを外しておき、先程作成したProfileを指定すると解決します。
![スクリーンショット 2021-12-10 0.48.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985195/cd2016fb-288d-4d2d-f741-2b2c68b67514.png)

# DeployGate
詳しい説明については省きます。

- DEPLOYGATE_API_KEY
⇒ アカウント設定 > APIKey に記載されているAPIキー

- IOS_DISTRIBUTION_HASH
⇒ アプリ配布ページURLに記載されているハッシュ値

- DEPLOYGATE_USER
⇒ アカウントに登録したユーザ名

# その他
App Extension (共有等) を使用する場合、追加でプロファイルを作成し、指定する必要があります。
基本的には、先程行った手順と同じです。

最後に main.yml の `Import Provisioning Profile` にApp Extensionのbase64形式のプロファイルをデコードする処理をこのように追記します。

```yml
touch ~/Library/MobileDevice/Provisioning\ Profiles/decoded-share-extension.mobileprovision
echo -n '${{ secrets.SHARE_EXTENSION_PROVISIONING_PROFILE }}' | base64 -d -o ~/Library/MobileDevice/Provisioning\ Profiles/decoded-share-extension.mobileprovision
```

[iOS Build Action](https://github.com/yukiarrr/ios-build-action)を使用してipaを出力する場合、こちらの指定が上手くいっていなかったため、一応ここに記載しておきます。

# 参考
https://www.mum-meblog.com/entry/research-detail/flutter-ios-ci-cd

https://zenn.dev/pressedkonbu/articles/254ca2fc3cd1ab