Flutterで作ったAndroidアプリをGitHubActionsを使ってGooglePlayに自動デプロイする
はじめに
最近subskunというAndroidアプリをリリースした。
最初のリリースの際はローカルでビルドして手動でストアにアップロードしたが、毎回それをしていては流石に面倒なので自動化したいと考えた。
そこで、GitHubActionsを使ってワークフローを組んでみることにした。
組んだワークフロー
ワークフローの全体は以下となった。リリース用のブランチであるmain
ブランチにマージがあったタイミングでワークフローが実行されるようにしている。
name: Deploy to Google Play
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.0.1'
channel: 'stable'
cache: true
- name: Run gen-l10n
run: flutter gen-l10n
- name: Build aab
run: |
echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > android/app/google-services.json
echo '${{ secrets.ANDROID_JKS_BASE64 }}' | base64 -d > android/app/release.keystore
export KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
export KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
export KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'
flutter build appbundle --release --flavor production --dart-define=FLAVOR=production --build-number='${{ secrets.ANDROID_BUILD_NUMBER }}' --obfuscate --split-debug-info=obfuscate/android
- name: Create service_account.json
run: echo '${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON }}' > service_account.json
- name: Upload artifact to Google Play
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJson: service_account.json
packageName: ${{ secrets.PACKAGE_NAME }}
releaseFiles: build/app/outputs/bundle/productionRelease/app-production-release.aab
track: production
status: completed
各ステップを解説
aabのビルドステップまでは以下の記事で紹介したワークフローと同じものを使っているので、すでにご存知の方はCreate service_account.json
まで飛ばしていただいて構わない。
Flutterで作ったAndroidアプリをGitHubActionsを使ってAppDistributionに自動デプロイする
actions/checkout@v3
レポジトリをチェックアウトしているだけなので割愛。
Set up Flutter
Flutter
の環境構築をしている。subosito/flutter-action
はそのためによく使われるActionだ。
ちなみにsubskunではFlutter3を使っている。
Run gen-l10n
subskunでは多言語対応しているので、以下のコマンドを走らせることでLocalization用のコードをビルドの前に生成しておく必要がある。
flutter gen-l10n
Build aab
ここでやっとビルドを走らせるが、まずはその下準備をする。
subskunではFirebaseを使っているので設定ファイルをGitHub ActionsのSecretsから生成している。
mkdir android/app/src/productionRelease
echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > android/app/src/productionRelease/google-services.json
以下ではAndroidアプリを署名するためのパスワードなどの準備をしている。jksファイルはバイナリなので、base64したものをGitHub ActionsのSecretsに設定し、ここでデコードしている。
echo '${{ secrets.ANDROID_JKS_BASE64 }}' | base64 -d > android/app/release.keystore
export KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
export KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
export KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'
ちなみに上記からも分かる通り、パスワードなどは環境変数から読み取る形式にしているのでandroid/app/build.gradle
のsigningConfigs
はこうなっている。
signingConfigs {
release {
keyAlias System.getenv('KEY_ALIAS')
keyPassword System.getenv('KEY_PASSWORD')
storeFile file('release.keystore')
storePassword System.getenv('KEYSTORE_PASSWORD')
}
}
次にやっとビルドだ。
dart-define
を使って環境の出し分けをおこない、--obfuscate
ではコードの難読化をおこなっている。
ビルド番号もSecretsから与えるようにしているが、アプリのバージョン番号から自動でビルド番号を読み取る方式にしようかどうか考え中。個人的にはiOSも含めてビルド番号はコードに依存させずに外部から与えるようにしたいと思っているが、もっと手軽にできるのであればそうしたいとも思っている。
flutter build appbundle --release --flavor production --dart-define=FLAVOR=production --build-number='${{ secrets.ANDROID_BUILD_NUMBER }}' --obfuscate --split-debug-info=obfuscate/android
2022-10-05追記
ビルド番号についてだが、コミット数から設定する方法を教えていただいた。以下の記事で紹介しているのでよければ読んでいただきたい。
FlutterアプリをGitHubActionsでビルドする際にコミット数をビルド番号として設定する
追記おわり
Create service_account.json
ストアへAPI経由でアップロードするためにサービスアカウントというのが必要になるので、そのためのファイルを作成している。
echo '${{ secrets.ANDROID_SERVICE_ACCOUNT_JSON }}' > service_account.json
サービスアカウント自体の作成については以下の記事を参考にさせていただいた。
Google Play Store向けサービスアカウントの作り方
Upload artifact to Google Play
準備が整ったのでいよいよGooglePlayにビルドをアップロードする。
ここでは0adkll/upload-google-play@v1
というActionを利用させていただいた。
- name: Upload artifact to Google Play
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJson: service_account.json
packageName: ${{ secrets.PACKAGE_NAME }}
releaseFiles: build/app/outputs/bundle/productionRelease/app-production-release.aab
track: production
status: completed
アプリのアップデート優先度やストアに公開する際のユーザーへの公開率、リリースノートなども設定することができる。もっと詳しく知りたい方はREADMEを参考にしていただきたい。
おわり
これでmain
ブランチへのマージをトリガーにしてPlayStoreへのデプロイを自動化することができた。
ここで自分の失敗談だが、ワークフローのデバッグ中にワークフローが成功してしまい、意図せずPlayStoreへアプリが審査に出されてしまった。アプリ自体に更新があったし近々審査に出そうと思っていたのでそのまま審査に出すことにしたが、意図せず審査に出したとしてもそれを削除することができずに困ってしまった。みなさんも注意していただきたい。