はじめに
最近、社内のアプリチームで、ストアへのアップロード手順を簡略するために
GitHub Actionsの導入を検討しています。
今回は、ビルドしたアプリを内部テストトラックに向けて配布するまでの手順を
ご紹介したいと思います。
手順
サービスアカウントの作成
Google Play Consoleにアップロードするとき、
認証のためにGoogle Cloud Platform(GCP)のサービスアカウント情報が必要になります。
ここではサービスアカウントの作成についての手順を紹介します。
Google Play ConsoleからGCPのプロジェクトページにアクセスする
追記: Google Play ConsoleからGCPの連携が不要になりました
記事公開前にGCPの連携が不要になっていました
「Publishing APIの設定の詳細」のページに飛ぶと、
日本語だとまだGCPに関する記述があるのですが、
英語版の場合は新しい手順になっていました。
基本的にサービスアカウントの作成からPlay Consoleへの招待までは変わらないです。
サービスアカウントを作成する


※アカウントのロールは参照者以上の権限にするようにしてください。
サービスアカウントの鍵情報を取得
サービスアカウントのキー情報を取得します。
キーを直接使用しない方法もあるのですが、
今回使用するAPIはサービスアカウントのキーが必要になるので、
こちらの方法を紹介します。
サービスアカウントキーを使わない方法は以下を参照してください
キー情報を取得


JSON形式でダウンロードします。
こちらのファイルは一度ダウンロードすると再取得できないため、
安全な場所に保管してください。
Google Play Consoleにサービスアカウントの権限を追加
Google Play Consoleの「ユーザーと権限」から、
先ほど作成したサービスアカウントのメールアドレスを追加します。
追加したメールアドレス
上記のメールアドレスを新しいユーザーとして招待します。
権限は上記のように設定しました。
GitHub Workflowの設定
シークレットの設定
GitHubリポジトリのSettingsタブページ内の、以下の赤枠部分を選択します。
各種シークレットを設定します。
今回は以下のキー名で設定しています。
- ENCODED_RELEASE_KEYSTORE
- 署名用のKeystoreファイルをBase64エンコードしたもの
- RELEASE_KEYSTORE_STORE_PASSWORD
- Keystoreファイルのパスワード
- RELEASE_KEYSTORE_ALIAS
- Keystoreが持つキー名
- RELEASE_KEYSTORE_ALIAS_PASSWORD
- 上記のキーのパスワード
- SERVICE_ACCOUNT_JSON
- 先ほどダウンロードしたサービスアカウントのJSON形式のキー情報
workflow設定ファイル
今回は、deploy_google_play_console.ymlという名前でファイルを追加しました。
プロジェクトの直下に以下のディレクトリ構成で配置します。
今回、Google Play Storeへのアップロードは以下のActionを使用しました。
設定が簡単で使いやすいです。
全体は以下の通りです
deploy_google_play_console.yml
name: Deploy Google Play Console
on:
# PRがmainにマージされ、クローズしたときに起動
pull_request:
branches:
- main
types: [closed]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
# 今回はJava 17でビルド
- name: set up JDK 17
uses: actions/setup-java@v1
with:
java-version: 17
# キーストア設定
# シークレットファイル配置用のディレクトリ作成
- name: Create secrets directory
run: |
mkdir secrets
# キーストアファイルをBase64からデコードしてファイルとして配置
- name: Decode Keystore
run: echo '${{ secrets.ENCODED_RELEASE_KEYSTORE }}' | base64 --decode > playstore.keystore
# デコードしたキーストアファイルをsecretsディレクトリ下に配置
- name: Copy Keystore
run: |
cp playstore.keystore secrets/playstore.keystore
# aabファイルを生成
- name: Generate AAB
run: ./gradlew :app:bundleRelease
# build.gradle.ktsから参照するための環境変数を設定
env:
KEYSTORE_ALIAS: ${{ secrets.RELEASE_KEYSTORE_ALIAS }}
KEYSTORE_ALIAS_PASSWORD: ${{ secrets.RELEASE_KEYSTORE_ALIAS_PASSWORD }}
KEYSTORE_STORE_PASSWORD: ${{ secrets.RELEASE_KEYSTORE_STORE_PASSWORD }}
# シークレットに設定したサービスアカウントキーをファイルとして配置
- name: Create service_account.json
id: createServiceAccount
run: echo '${{ secrets.SERVICE_ACCOUNT_JSON }}' > service_account.json
# Google Play Storeの内部テストトラックにアップロードする
- name: Deploy to Play Store
id: deploy
uses: r0adkll/upload-google-play@v1.1.2
with:
serviceAccountJson: service_account.json
packageName: your.app.packagename
releaseFiles: app/build/outputs/bundle/release/app-release.aab
track: internal
# 未公開のアプリはstatusをdraftに指定する必要あり
status: draft
ビルド設定
今回は.ktsでビルドしています。
念の為ローカルでもビルドできるために、署名周りは以下のように設定しています。
// 署名キー用のシークレットプロパティファイル(今回はローカルでのみ使用)
val secrets = readProperties(file("../secrets/secrets.properties"))
// リポジトリ上にsecrets.propertiesはアップしないので、読み込まなかったときはエラーログだけ出す
fun readProperties(propertiesFile: File) = Properties().apply {
try {
propertiesFile.inputStream().use { fis ->
load(fis)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
android {
signingConfigs {
create("release") {
// secrets/secrets.propertiesが無ければ、環境変数を使用する
// ローカルビルドの設定が不要であれば、System.getenvのみで可
keyAlias = secrets["alias"] as? String ?: System.getenv("KEYSTORE_ALIAS")
keyPassword = secrets["aliasPassword"] as? String ?: System.getenv("KEYSTORE_ALIAS_PASSWORD")
storeFile = file("../secrets/playstore.keystore")
storePassword = secrets["password"] as? String ?: System.getenv("KEYSTORE_STORE_PASSWORD")
}
}
// ...
buildTypes {
release {
// リリースビルド時に署名用のキーを設定
signingConfig = signingConfigs.getByName("release")
// ...
}
}
// ...
}
Java 17でビルドするので、ターゲットバージョンも設定
android {
// ...
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
// ...
}
動かしてみる

PRを作成して、mainにマージしてみます。

無事Google Play Consoleにアップロードできました。
(ビルドが一発で通らず、だいぶPRを作り直しました…)

Google Play Consoleにアップされました。
今回はストアにリリースしていないアプリなので、statusはdraft(未公開)になります。
今後の課題
- 複数人で作業する場合のGitHubの権限設定
- テスト・ビルドの結果の通知
- Firebase App Distribution向けの配布
- 現状は毎回フルビルドが走るので、変更が無い部分はキャッシュできるかどうか
参考にさせていただいた記事
サービスアカウントの作成・ビルド・デプロイまでまとまっており、とても参考になりました。
おわりに
お疲れ様でした。
今回触ってみた感じだと、GitHub Actionsでアプリの自動リリースを行えると、
- ビルド後にアプリを配布し忘れる、といったようなケアレスミスを減らせる
- ローカルマシンでリリースビルドする必要がなくなるので、個々のマシンでリリース用のKeystore設定が不要になり、セキュリティが高くなる
などのメリットがありそうだと感じました。
今後、積極的に導入していきたいと思います。
運動通信社について
私たち運動通信社は、共に働きたい方を募集しています。
ご応募の際は、下記のリンクの採用情報をご覧ください。