Building React Native Android APKs with GitHub Actions
Building React Native Android APKs with GitHub Actions ⚙️
In the ever-evolving landscape of mobile development, automation is key to maintaining a streamlined workflow. Today, I’m excited to share how I’ve automated the process of building Android APKs for a React Native project using GitHub Actions, a powerful CI/CD tool that’s built right into your repository.
This guide will walk you through setting up a secure and efficient pipeline that automatically generates a signed Android APK with every push to your designated branches.
Prerequisites
Before setting up the workflow, you’ll need to prepare a few key assets.
Android Keystore: You’ll need an Android keystore file for signing your release APK. This is crucial for app security and for publishing to the Google Play Store. If you don’t have one, you can generate it using the
keytool
command-line utility.1
keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
Running this command will prompt you for several details, including a password for your keystore and a password for your key. Remember these passwords, as you’ll need them later. This will create a file named
my-release-key.keystore
.Base64 Encode the Keystore: For security, we’ll store the keystore file as a GitHub secret. Secrets are plain text, so we need to encode the binary keystore file into a string. The best practice is to use Base64 encoding.
On macOS/Linux:
1
base64 my-release-key.keystore | tr -d '\n' | tee keystore_base64.txt
This command encodes the file and removes any newlines, ensuring the output is a single, continuous string, which is ideal for a secret.
On Windows (PowerShell):
1
[Convert]::ToBase64String([IO.File]::ReadAllBytes("my-release-key.keystore")) | Out-File -FilePath keystore_base64.txt -Encoding ascii
This will create a file
keystore_base64.txt
containing the encoded keystore string.
Setting up GitHub Secrets 🔐
GitHub Secrets are encrypted environment variables that you can use in your workflows. They are the safest way to handle sensitive data like passwords and keys.
- Navigate to Repository Settings: Go to your GitHub repository and click on the “Settings” tab.
- Access Secrets: In the left sidebar, click on “Secrets and variables” then “Actions”.
- Add Repository Secrets: Click the “New repository secret” button to add each of the following secrets:
RELEASE_KEYSTORE_BASE64
: Copy and paste the entire contents of yourkeystore_base64.txt
file here.RELEASE_STORE_PASSWORD
: The password for your keystore.RELEASE_KEY_ALIAS
: The alias you gave your key (e.g.,my-key-alias
).RELEASE_KEY_PASSWORD
: The password for your key.
The GitHub Actions Workflow File
Create a new file at .github/workflows/android-build.yml
in your project’s root directory. This is where you’ll define the build pipeline.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
name: Build React Native Android
on:
# The workflow will run on pushes to 'main' branches
# and on pull requests targeting 'main'.
push:
branches: [ main ]
pull_request:
branches: [ main ]
# Jobs are a series of steps that run on a runner machine.
jobs:
build-android:
# Use the latest Ubuntu runner, a standard choice for builds.
runs-on: ubuntu-latest
# Optional: You can specify an environment for advanced security rules.
# environment: build
steps:
# Step 1: Check out the repository code.
- name: Checkout repository
uses: actions/checkout@v4
# Step 2: Set up the correct Node.js environment.
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'yarn' # This caches the yarn dependencies to speed up future builds.
# Step 3: Install all project dependencies.
- name: Install Yarn dependencies
run: yarn install --frozen-lockfile
# Step 4: Set up Java, a requirement for Android builds.
- name: Set up Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
# Step 5: Set up the Android SDK and required build tools.
- name: Set up Android SDK
uses: android-actions/setup-android@v3
# Step 6: Decode the base64-encoded keystore and write it to a file.
- name: Decode Keystore
run: |
echo "$" | base64 -d > android/app/my-release-key.keystore
# Step 7: Create the keystore.properties file for Gradle.
- name: Create keystore.properties
run: |
echo "storeFile=my-release-key.keystore" > android/keystore.properties
echo "storePassword=$" >> android/keystore.properties
echo "keyAlias=$" >> android/keystore.properties
echo "keyPassword=$" >> android/keystore.properties
# Move the properties file to the correct location for Gradle.
mkdir -p android/keystores
mv android/keystore.properties android/keystores/keystore.properties
# Step 8: Build the Release APK.
- name: Build Android Release
run: |
# Make sure the Gradle wrapper is executable.
chmod +x ./android/gradlew
# Use Gradle to assemble the release build.
cd android && ./gradlew assembleRelease
# Step 9: Upload the resulting APK as a workflow artifact.
- name: Upload Release APK
uses: actions/upload-artifact@v4
with:
name: app-release.apk
path: android/app/build/outputs/apk/release/app-release.apk
Breaking Down the Workflow Steps
The workflow’s logic is a sequence of clearly defined steps, each with a specific purpose.
- Trigger & Runner: The workflow starts on a
push
orpull_request
to the specified branches. It runs on a hosted runner, in this case,ubuntu-latest
. - Checkout & Setup: The
actions/checkout@v4
,actions/setup-node@v4
,actions/setup-java@v3
, andandroid-actions/setup-android@v3
actions are the foundation. They pull the code and configure the necessary environment (Node.js, Java, and Android SDK) for a successful build. - Dependency Installation: The
yarn install
command downloads all the necessary project packages. Using the--frozen-lockfile
flag ensures a reproducible build by using the exact versions from youryarn.lock
file. - Keystore Handling: This is the most crucial part for signing the APK. We use the
base64 -d
command to decode the secret string back into a binary file. Then, we create akeystore.properties
file with our secret credentials, which Gradle uses to sign the APK. - Build Command:
cd android && ./gradlew assembleRelease
is the standard command to build a production-ready, signed Android APK. - Artifact Upload: The
actions/upload-artifact@v4
action is a lifesaver. It takes the newly built APK file and saves it as an artifact in your workflow run. You can easily download it from the GitHub Actions tab for testing or distribution.
By automating this process, you’ve saved countless hours and reduced the potential for human error in your release cycle. The result is a consistent, reliable, and secure build process that is a cornerstone of professional mobile development.