Deploying Unity 3D to Play Store in Github Actions with Fastlane

I always enjoy building games using Unity 3D during my free time. I always like to make sure the auto-deployment is ready to ensure that I can focus on my development instead of the troublesome building process for every release. Although Unity does provide Unity Cloud Build service to us, I would prefer Github Actions for my build. I’m going to demonstrate how I do it in this blog post.

Prerequisite 1 – Acquiring Unity License

Before we are able to set up the auto deployment, we need to acquire unity license. Please complete the steps on how to acquire unity license.

Prerequisite 2 – Getting Google Play Console Ready

To start with auto-deployment to Play Store, you need at least to get your app out of the “Draft” status in Google Play Console. That means you have to at least manually upload a version and publish it to “Internal Testing”.

Once you have the Unity license and Google Play Console ready, you can continue to set up the auto-deployment in Github Actions.

1. Install Fastlane

I always use Fastlane for app submission to Play Store. Fastlane is a great tool to facilitate building and releasing the mobile app into the Play Store. The recommended way to install Fastlane is by using Bundler. You can install Bundler using the following command.

gem install bundler

Next, create a Gemfile file at the root of your Unity project and add the following content.

source "https://rubygems.org"

gem "fastlane"

Then, run bundler install in your terminal. It should create a Gemfile.lock file in the root of your project.

2. Create a Google Play Service Account

To publish your app to Play Store, You will need a Google Play Service account to access Google Play Console API.

Follow the Setup section of the Fastlane supply documentation to create a service account. After you’ve completed all the steps, you should get a .json credential file.

Then, go to Github > Your Repository > Settings > Secrets and add the content of the .json file as the new secret with the name GOOGLE_PLAY_KEY_FILE.

3. Add Keystore into secrets

Now, we need to base64-encoding the Keystore file. You will need to create a new Keystore if you haven’t done so. Run the following command and copy the output.

base64 your-keystore.keystore

After that, we will need to add four secrets to the Github repository. Head to Github > Your Repository > Settings > Secrets and add the following key and value.

ANDROID_KEYSTORE_BASE64 – Content of the base64 encoded keystore.

ANDROID_KEYSTORE_PASS – Password of your keystore.

ANDROID_KEYALIAS_NAME – Alias for your keystore.

ANDROID_KEYALIAS_PASS – Password for your keystore’s alias.

4. Setup Fastlane

At this point, you should have at least eight secrets in you Github repository’s secrets:

  • ANDROID_KEYALIAS_NAME
  • ANDROID_KEYALIAS_PASS
  • ANDROID_KEYSTORE_BASE64
  • ANDROID_KEYSTORE_PASS
  • GOOGLE_PLAY_KEY_FILE
  • UNITY_EMAIL
  • UNITY_LICENSE
  • UNITY_PASSWORD

Let’s define the lane in Fastlane. Create fastlane/Appfile with the following codes:

for_platform :android do
  package_name(ENV["ANDROID_PACKAGE_NAME"])
  json_key_file(ENV["GOOGLE_PLAY_KEY_FILE_PATH"])
end

After that, add fastlane/Fastfile and add the following codes:

platform :android do
  desc "Upload a new Android internal version to Google Play"
  lane :internal do
    upload_to_play_store(track: 'internal', release_status: 'completed', aab: "#{ENV['ANDROID_BUILD_FILE_PATH']}")
  end
end

Here, we’ve created a lane that uses the upload_to_play_store action to upload the app to the internal testing track. You can change the `track` parameter if you want to upload to a different track.

5. Add jobs to Github workflow

Last but not least, you need to create the Github Action workflow. Create .github/workflow/build-android.yml and add the following codes:

name: Deploy Android 😎

on:
  push:
    tags:        
      - '*' 

jobs:
  buildForAndroidPlatform:
    name: Build For Android Platform
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/cache@v2
        with:
          path: Library
          key: Library-Android
      - uses: game-ci/unity-builder@v2
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
        with:
          targetPlatform: Android
          androidAppBundle: true
          androidKeystoreName: user # This file won't exist, but this property needs to exist.
          androidKeystoreBase64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
          androidKeystorePass: ${{ secrets.ANDROID_KEYSTORE_PASS }}
          androidKeyaliasName: ${{ secrets.ANDROID_KEYALIAS_NAME }}
          androidKeyaliasPass: ${{ secrets.ANDROID_KEYALIAS_PASS }}
      - uses: actions/upload-artifact@v2
        with:
          name: build-Android
          path: build/Android

  releaseToGooglePlay:
    name: Release to the Google Play Store
    runs-on: ubuntu-latest
    needs: buildForAndroidPlatform
    env:
      GOOGLE_PLAY_KEY_FILE: ${{ secrets.GOOGLE_PLAY_KEY_FILE }}
      GOOGLE_PLAY_KEY_FILE_PATH:
        ${{ format('{0}/fastlane/google-fastlane.json', github.workspace) }}
      ANDROID_BUILD_FILE_PATH: ${{ format('{0}/build/Android/Android.aab', github.workspace) }}
      ANDROID_PACKAGE_NAME: ${{ secrets.ANDROID_PACKAGE_NAME }}
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
      - name: Download Android Artifact
        uses: actions/download-artifact@v2
        with:
          name: build-Android
          path: build/Android
      - name: Add Authentication
        run: echo "$GOOGLE_PLAY_KEY_FILE" > $GOOGLE_PLAY_KEY_FILE_PATH
      - name: Set up Fastlane
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: 2.7.2
          bundler-cache: true
      - name: Upload to Google Play Internal
        uses: maierj/fastlane-action@v2.0.1
        with:
          lane: 'android internal'
      - name: Cleanup to avoid storage limit
        if: always()
        uses: geekyeggo/delete-artifact@v1
        with:
          name: build-Android

Lastly, you will need to add the ANDROID_PACKAGE_NAME into Github repository’s secret.

Bonus: Controlling App Version

By default, unity/game-ci uses semantic versioning the format of <major>.<minor>.<patch>. It will use the version of your latest tag for <major>.<minor> and keep incrementing the number <patch> based on the number of the commit. You can change the behaviour by changing the versioning parameters of the game-ci/builder action.

Congratulations! You have done all the steps and you will have your auto-deployment for your Unity 3D games.

Leave a Reply

%d bloggers like this: