Stanislav Khromov

Looking for building iOS bundles with Capacitor? Check out this blog post instead!

This post has been updated on 2023-06-06 to work with Capacitor 5.

In this post we will set up a GitHub Actions workflow for a Capacitor app that will produce a signed app bundle, ready for upload to Google Play Console.

At a high level, we will:

  • Set up our key store and signing keys
  • Adding our key store and signing keys to GitHub Secrets
  • Creating a GitHub Actions workflow

Let’s get started! 🀩

Generating a key store

You probably already have a key store to sign your app releases, but in case you don’t here’s how to create one:

keytool -genkey -v -keystore android/release.jks -keyalg RSA -keysize 2048 -validity 10000 -alias release

Follow the prompts until it asks you if the data is correct, enter yes to save your key. Don’t forget to also add it to .gitinore so you don’t accidentally commit it to your repo, the keystore should be kept secret.

Adding the key store and password as GitHub Secrets

In GitHub we can add secrets for our repository under Settings > Secrets > Actions

We quickly run into a snag however, because secrets can only be strings, and the key store is actually binary data.

There’s a handy CLI utility called base64 , which should be preinstalled on most Linux distros. Using it we can convert our binary file into a string representation, let’s run:

base64 android/release.jks > android/release.jks.base64

If we now open android/release.jks.base64 we should see a normal text file.

Now we can add it as a secret named RELEASE_KEYSTORE. It should look something like this:

ℹ️ Don’t worry about the base64 representation – will convert it back to a file in our GitHub Action.

Let’s also add the key store password as RELEASE_KEYSTORE_PASSWORD. Now it should look like this:

Adding our GitHub Action workflow

It’s finally time to add our workflow! Add the following file to .github/workflows/android-build.yml

name: Build Android

on:
  push:
    branches:
      - master

jobs:
  build:
    name: Build APK
    runs-on: ubuntu-latest
    steps:
      - name: Checkout source
        uses: actions/checkout@v3

      - name: Setup java
        uses: actions/setup-java@v3
        with:
          distribution: 'zulu'
          java-version: '17'

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 19.x

      - name: Install app dependencies
        run: npm install

      - name: Build Svelte app
        run: npm run build:static

      - name: Capacitor update
        run: npx cap update

      - name: Capacitor copy
        run: npx cap copy

      - name: Build app bundle
        run: cd android && ./gradlew bundle

      - name: Extract Android signing key from env
        run: |
          echo "${{ secrets.RELEASE_KEYSTORE }}" > android/release.jks.base64
          base64 -d android/release.jks.base64 > android/release.decrypted.jks

      - name: Sign dev build
        run: jarsigner -keystore android/release.decrypted.jks -storepass "${{ secrets.RELEASE_KEYSTORE_PASSWORD }}" -signedjar ./android/app/build/outputs/bundle/release/app-release-signed.aab ./android/app/build/outputs/bundle/release/app-release.aab release

      - name: Upload release bundle
        uses: actions/upload-artifact@v3
        with:
          name: app-release
          path: android/app/build/outputs/bundle/release/app-release-signed.aab
          retention-days: 60

ℹ️ You might want to tweak a some things such as the branch to build on, preferred Java version and how much retention you want for your output artifacts using the retention-days configuration option.)

After pushing your change you can navigate to the Actions tab in your repo where you should see your build running.

❌ If your build does not finish, please try building locally using the workflow steps above, there might be something wrong with your Capacitor configuration.

Once your build has run successfully, you can download your bundle directly from the build run page!

From here you can directly upload the signed bundle in the Play Console! πŸš€

ℹ️ Note that you have to bump the versionCode in android/app/build.gradle for every new version you intend to upload to the Play store.

Links and acknowledgements

A special thanks to the posts below, without which this post could not exist. πŸ™‚

Photo by Liam Briese on Unsplash

Full-stack impostor syndrome sufferer & Software Engineer at Schibsted Media Group

View Comments

Next Post