Automate Android App Publishing on Play Store using GitHub Actions

In this post, I’ll show how I managed to automate android app publishing on Play Store.

I had ZERO knowledge about CI/CD before I tried this.😅

I tried a couple of plugins like Fastlane, CircleCi, Triple-T, but I found GitHub Actions super easy(At-least for me 😉).

You can find more details about Github Actions here.

I’ll cover the following steps:

  • Checkout
  • Set up JDK 1.8
  • Build with Gradle
  • Run Unit tests(Optional)
  • Build Release Bundle(AAB)
  • Sign Bundle
  • Upload Bundle(Optional)
  • Prepare Play Store Service Account
  • Deploy to Play Store
  • Notify Build status on Slack(Optional)

Before you start, here are some basic Workflow syntaxes that I have used.

  • name — full name of your workflow.
  • on— name of the GitHub event that triggers the workflow.
  • jobs — jobs to be run. We’ll use build in our example.

You can find more syntaxes here.

Step 1: Checkout

- name: Checkout
uses: actions/checkout@v2

Refer to the following repo for details.

Step 2: Set up JDK 1.8

- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8

We’ll use id for steps for which we want status to be reported in slack notification.

Step 3: Build with Gradle

- name: Build with Gradle
id: build
run: ./gradlew build

Step 4: Run Unit tests

- name: Unit tests
id: tests
run: ./gradlew test

Step 5: Build Release Bundle(AAB)

Here are some benefits of Android App Bundle over APK on the app store

  • Smaller Download Size
  • On-Demand App features
  • Asset-only modules
- name: Build Release AAB
id: buildRelease
run: ./gradlew bundleRelease

More information on App Bundles is available here.

Step 6: Sign Bundle

  • KeyStore
  • Alias
  • KeyStore Password
  • Key Password

If you don’t have one already, you can refer to Generate an upload key and Keystore to create one.

To use these keys from the workflow, we’ll add it to GitHub Secrets. So it’ll not be exposed. To add Secrets, open your repository and go to Settings.

Image for post
Image for post
Settings from your Repository

Now click on Secrets from left panel

Image for post
Image for post
Secrets from the settings panel

Then click on New Secret to add a new secret value.

Here for the KeyStore file, we need to upload base64 value. I use this link to generate base64 from the file.

Image for post
Image for post
Add a new Secret

Add the following Secrets in your repository

  • SIGNING_KEY — base64 text of your Keystore file
  • ALIAS — your alias name
  • KEY_STORE_PASSWORD — password of your Keystore
  • KEY_PASSWORD — your key password
- name: Sign AAB
id: sign
uses: r0adkll/sign-android-release@v1
with:
releaseDirectory: app/build/outputs/bundle/release
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
alias: ${{ secrets.ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}

Refer to the following repo for details about this action.

Step 7: Upload Artifact

- name: Upload AAB
id: uploadArtifact
uses: actions/upload-artifact@v1
with:
name: app
path: app/build/outputs/bundle/release/app-release.aab

It’ll upload your signed bundle and shown as an artifact. you can download it from there.

Image for post
Image for post
Uploaded Artifact

Step 8: Prepare Play Store Service Account

Add the following Secret in your repository

  • SERVICE_ACCOUNT_JSON — content of JSON file
- name: Create service_account.json
id: createServiceAccount
run: echo '${{ secrets.SERVICE_ACCOUNT_JSON }}' > service_account.json

If you don’t have a service account, follow the below steps to create one.

  • Login with Owner account to Google Play
Image for post
Image for post
  • Open ‘Settings’>’API access’
Image for post
Image for post
  • Click ‘Create new project’ (if not created earlier)
  • Click ‘Create Service Account’
Image for post
Image for post
  • Click Navigate to the Google API Console.
Image for post
Image for post
  • Click ‘Create Service Account’ at Google API Console.
  • Enter in ‘Service account name’ field the name of the account.
Image for post
Image for post
  • Click ‘Create’.
  • Save downloaded JSON file.
  • Return back to Google Play console.
  • Click ‘Done’ and ensure the new service account appears in the list.
  • Click the ‘Grant Access’ button.
  • Choose ‘Release Manager’ in ‘Role’ dropdown (probably is already selected by default).
  • Set ‘Never’ in ‘Access expire date’ (should be selected by default).

Step 9: Deploy to Play Store

- name: Deploy to Play Store (BETA)
id: deploy
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJson: service_account.json
packageName: com.package
releaseFile: app/build/outputs/bundle/release/app-release.aab
track: beta
whatsNewDirectory: whatsnew/

Refer to the following repo for details about this action.

Step 10: Notify Build status on Slack

We need to set an environment variable for a Slack webhook URL to send a message. Add env before starting steps

env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

and the following action to send a message.

- name: Notify on Slack
uses: act10ns/slack@v1
with:
status: ${{ job.status }}
steps: ${{ toJson(steps) }}
if: always()

If you don’t know about Slack Webhook, check this.

Refer to the following repo for details about this action.

Image for post
Image for post

Congrats, you are done with the automating of the app publishing process.

🚀EXTRA is always GOOD

  1. On Push CI — When pushed in any branch except master, I only need to Build it with Gradle.
  2. Deploy App CI — When pushed to master or any PR is merged to master, I need to deploy the app.

Here are the workflows I use.

I haven’t written any unit tests and I didn’t need artifact so I have skipped that steps in following gist. You can get that code above if needed.

On Push CI

Deploy App CI

Here is how Slack's message looks like for both workflows.

Image for post
Image for post

You can find more actions in the marketplace.

Written by

Android Developer since 2017 with knowledge in Java, Kotlin, Firebase, React-native, SQLite, Realm, Room, PHP.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store