Mobile DevOps with GitLab, Part 2 - Code signing for Android with GitLab

Sep 28, 2022 · 4 min read · Leave a comment
Darby Frey GitLab profile

In Part 1 of this tutorial series, we talked about a new feature in GitLab called Project-level Secure Files. With Project-level Secure Files, you can securely store your build keys as part of your project in GitLab, and avoid some painful problems caused by lost keystore files.

In this blog post, I'll show you how to create a Keystore file and use it to sign an Android application. Then I'll show you how to quickly create a CI pipeline in GitLab using Project-level Secure Files.

Generate a private signing key

The first thing you'll need is a Keystore file. This file is used to securely sign the application. You can generate a Keystore file from your machine by running the following command:

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

During this process, you'll be asked to create a new password for the Keystore file and provide some information about you and your organization. See the example below:

Generate Android Keystore

Configure your application

The next step is to set some environment variables and update build.gradle to add the new signing configuration. First, set the following environment variables in either a .env file or in the shell via export.

With the environment variables set, the next step is to update the build configuration to use the new Keystore in the build process. In the app/build.gradle file add the following configuration inside the Android block for the release signing config.

android {
    ...
    defaultConfig { ... }
    signingConfigs {
        release {
           storeFile file(System.getenv('ANDROID_KEY_STOREFILE'))
           storePassword System.getenv('ANDROID_KEYSTORE_PASSWORD')
           keyAlias System.getenv('ANDROID_KEY_ALIAS')
           keyPassword System.getenv('ANDROID_KEYSTORE_PASSWORD')
        }
    }
    buildTypes {
        release {
            ...
            signingConfig signingConfigs.release
        }
    }
}

Save these changes to the app/build.gradle file, and run the build locally to ensure everything works. Use the following command to run the build:

./gradlew assembleRelease

If everything worked you'll see a message saying BUILD SUCCESSFUL.

Configure project

With the build running locally, it takes just a couple of steps to get it running in GitLab CI. The first step is to upload your Keystore file in GitLab.

  1. On the top bar, select Menu > Projects and find your project.
  2. On the left sidebar, select Settings > CI/CD.
  3. In the Secure Files section, select Expand.
  4. Select Upload File.
  5. Find the file to upload, select Open, and the file upload begins immediately. The file shows up in the list when the upload is complete.

Upload Secure File

List Secure Files

The next step is to set the CI variables in your project.

  1. On the top bar, select Menu > Projects and find your project.
  2. On the left sidebar, select Settings > CI/CD.
  3. In the Variables section, select Expand.
  4. Create entries for the three environment variables set earlier: ANDROID_KEY_ALIAS, ANDROID_KEY_STOREFILE, ANDROID_KEYSTORE_PASSWORD.

List Secure Files

CI/CD pipelines

Once the project is configured, the final step is to create the build configuration in the .gitlab-ci.yml file. Below is a sample file.

stages:
  - build

build_android:
  image: fabernovel/android:api-31-v1.6.1
  stage: build
  variables:
    SECURE_FILES_DOWNLOAD_PATH: './'
  script:
    - apt update && apt install -y curl
    - curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/devops-for-mobile-apps/load-secure-files/-/raw/main/installer" | bash
    - ./gradlew assembleRelease
  artifacts:
    paths:
      - app/build/outputs/apk/release

A few interesting bits from this configuration:

  1. Image: https://github.com/faberNovel/docker-android provides a collection of prebuilt Docker images that work great for CI systems. Find the right version for your project in Docker Hub https://hub.docker.com/r/fabernovel/android/tags.
  2. Script: Depending on the image, you may need to install curl; the first line of the example script installs curl to be used in the second line to download and execute the load-secure-files tool.
  3. Variables: SECURE_FILES_DOWNLOAD_PATH tells load-secure-files where to download the Keystore file.
  4. Artifacts: Make the build output available to be downloaded from the CI job, or used in subsequent jobs in the pipeline.

Commit the changes to your .gitlab-ci.yml file and after you push the changes to GitLab the build will start.

Take a look at this branch in the sample project for reference.

Give it a try, and let us know what you think in the feedback issue. Then, check out Part 3, which deals with code signing for iOS.

Cover image by Teddy GR on Unsplash

“In this second part in our tutorial series on mobile DevOps, learn how to use Project-level Secure Files to sign an Android application.” – Darby Frey

Click to tweet

Open in Web IDE View source