🛠️

[Flutter] GitHubActionsを使ってAndroidアプリの配布を自動化したときの覚書

に公開

色々なところで詰まって時間を食ったので、また同様の作業をするときに自分が見返せるようにメモを残しておきます。

修正

1/20 upload-google-playのtrackをinternalに修正
2/22 ブランチを作成しただけではアクションが動作しないので、判定を追加

詰まったところ

ブランチでGitHub Actionsの動作を確認する

  • .github/actions/workflows/xxx.ymlはmainブランチにファイルが存在しないと実行されない。
  • 空のファイルで良いので.github/actions/workflows/android_build_stg.ymlのようなファイルを一時的にmainにpushしておくとブランチからトリガーイベントを実行しても想定通りの動作チェックが行える。

jksファイルをbase64でエンコードした文字列を環境変数にセットする

  • 最初に参考にしていたサイトで、jksファイルをsecretsに登録するとか書かれていたけどこんなものstringとして登録できないしどうするんだって詰まっていた。
  • 1回base64エンコードして文字列にした上で環境変数にセットして、利用するときにデコードする。
  • 直接クリップボードにコピーしても良いと思うけど。
cmd
$ openssl base64 -A -in /path/to/jks/xxx.jks > encode.txt

pubspec.ymlにプライベートリポジトリの内容が含まれている

  • GitHub Actionsの実行ログで以下のようなエラーが発生した。原因としては、依存関係として指定されたリポジトリへのアクセス権限が不足しているのが問題。
Resolving dependencies...
Git error. Command: git clone --mirror git@github.com:xxx.git /home/runner/.pub-cache/_temp/dirGTJFEZ
stdout: 
stderr: Cloning into bare repository '/home/runner/.pub-cache/_temp/dirGTJFEZ'...
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
exit code: 128

対応するためには、以下のような作業が必要。

公開鍵をGitHubに登録する

  • 例えば以下のような形でSSH鍵を作成し、生成されたSSHの公開鍵(~/.ssh/id_ed25519_github_actions.pub)を読み出したいリポジトリのDeploy Keysに登録する
    • ここで間違えて呼び出し側のGitHubに追加していて無駄な時間をかけた
    • パスフレーズは登録しない
cmd
$ ssh-keygen -t ed25519 -C "github-actions" -f ~/.ssh/id_ed25519_github_actions
  • 秘密鍵を(~/.ssh/id_ed25519_github_actions)呼び出し側のGitHub Actionsに登録する
    • GitHubリポジトリの [Settings] > [Secrets and variables] > [Actions] > [New repository secret] をクリック
    • 名前を例えばSSH_PRIVATE_KEYとし、秘密鍵の内容をペーストします。

GitHub ActionsでSSHを使う

今回はInstall SSH Keyのactionを利用した

  • Install SSH Key
  • secretsにSSH_KNOWN_HOSTSとして上で作成した鍵のknown_hostsを登録しておく。
    • ssh-keyscan -t ed25519 github.com >> known_hosts

buildで最初のステップにInstall SSH keyを追加

android_build_stg.yml
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Install SSH key
        uses: shimataro/ssh-key-action@v2
        with:
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          known_hosts: ${{ secrets.SSH_KNOWN_HOSTS }}

サービスアカウントを作成する

  • FirebaseDistributionにアップロードするときにサービスアカウントを使った認証を行うことを推奨されていたが、GCPにサービスアカウント作るのが嫌でFIREBASE_TOKENを使っていた。
  • 実際作ること自体は参考サイトなどを参照すればそこまで大変なことではないが、鍵の管理などはこれまでより厳重に気を付ける必要がある。
  • FIREBASE_TOKEN migration

GooglePlayStoreに自動アップロードする

参考にしたサイトでは(私にとって)不要な権限をつけ過ぎていたので一部の情報を除外した。

  1. 参照者権限で対象アプリのサービスアカウントを作成して鍵をダウンロードする
    • ここで作成した鍵をGitHubActionsのSecretsにPLAY_SERVICE_ACCOUNT_JSONとして登録した。
  2. GooglePlayConsoleで1. で作成したサービスアカウントに対して権限を付与する
    • リリースノートなどを別途設定してからリリースに進めたいため、誤って本番リリースされないように本番公開向けの権限は付与しない。
  3. 内部テスター向けに配布するアクションを追加する
android_build_prd.yml
- name: Upload aab to Google Play Store
  uses: r0adkll/upload-google-play@v1
  with:
    serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
    packageName: your.package.name
    track: internal
    releaseFile: './build/app/outputs/bundle/productionRelease/app-production-release.aab'

ブランチを作成しただけではアクションが動かない

こんな記述になっていたのだが、この形だとupload-development/**のbranchを作成したとしてもそこに空pushを1回しなければ動作しない形になってしまっていた。(当たり前だが)
Xcode Cloudだとそれで動作していたので修正が必要となった。

android_build_stg.yml
name: "[DEV] Build and Publish Android"
on:
  push:
    branches:
      - 'upload-development/**'
      - 'upload-apk/**'
    paths-ignore:
      - 'README.md'

jobs:
  # Build job
  build:
    runs-on: ubuntu-latest

createのイベントを追加し、指定したブランチがcreateされた場合にも処理を行う形とした。
指定されたブランチ以外では、2秒ほどでスキップされてワークフローが終了する。

android_build_stg.yml
name: "[DEV] Build and Publish Android"
on:
  push:
    branches:
      - 'upload-development/**'
      - 'upload-apk/**'
    paths-ignore:
      - 'README.md'
+  create:

jobs:
  # Build job
  build:
    runs-on: ubuntu-latest
+    if: >
+      github.ref_type == 'branch' &&
+      startsWith( github.ref_name, 'upload-development' ) ||
+      startsWith( github.ref_name, 'upload-apk' )

参考にした記事

Discussion