How to make React Native builds with Github Actions

Sanjin Sehic
ScaleUp
Published in
6 min readOct 31, 2023

Introduction

In the fast-paced world of mobile app development, efficiency and automation have become one of the most important things for success. As React Native continues to gain popularity for its cross-platform capabilities, it’s essential for developers to find smooth ways to build, test, and deploy their applications. That’s where Continuous Integration and Continuous Deployment (CI/CD) come into play.

GitHub Actions, a feature of the popular code hosting platform GitHub, offers a powerful tool for setting up your CI/CD processes. By integrating React Native with GitHub Actions, you can simplify and enhance your app development journey.

In this article, we will explore the how to set up CI/CD with React Native using GitHub Actions. We’ll walk you through the steps for both iOS and Android platforms separately, ensuring that you have a clear understanding of how to smooth your mobile app development process.

Building iOS app and getting IPA file

First thing that you will need to do is to go to your Apple console and make Signing certificate and two Provisioning profiles (App store and Ad hoc).
Then you will need to create one folder (let’s call it ios-build) where you will store the following:

Signing certificate

Go to your Keychain access and find that Signing certificate you have created on Apple console and export it as p.12 file to ios-build folder. You will need to input password for that certificate that we will need later, so it’s best to write that password somewhere.

Provisioning profiles

Your provisioning profiles should have this path: Users/{yourUsername}/Library/MobileDevice/Provisioning\ Profiles. Find those two profiles you have created before and copy them to ios-build folder.
Then go to that folder and do this command:

tar czvf mobile-pp.tgz *.mobileprovision

Keychain password for the build machine

You need to create a password you will use to setup and add data to the GitHub Action macOS runner’s Keychain. There is a few options how to do this but for me simplest one is this:

pass generate temp/temp 18

ExportOptions.plist

For this you will have to archive your app in xcode with that Ad hoc provisioning profile you created. After it archives you should be able to export IPA file and you should be able to access your ExportOptions.plist. It should look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>compileBitcode</key>
<true/>
<key>destination</key>
<string>export</string>
<key>method</key>
<string>ad-hoc</string>
<key>provisioningProfiles</key>
<dict>
<key>your_bundle_id</key>
<string>Ad Hoc</string>
</dict>
<key>signingCertificate</key>
<string>Apple Distribution</string>
<key>signingStyle</key>
<string>manual</string>
<key>stripSwiftSymbols</key>
<true/>
<key>teamID</key>
<string>your_team_id</string>
<key>thinning</key>
<string>&lt;thin-for-all-variants&gt;</string>
</dict>
</plist>

Copy that file to ios-build folder.

Now that you have everything set in ios-build folder you will need to do repository secrets setup. To do this go to your project on github, press Settings, then Secrets and variables and then Actions. There you will see button ‘New repository secret’. You are going to need five repository secrets. Here they are:

BUILD_CERTIFICATE_BASE64

Go to your ios-build folder and do this:

base64 -i Certificates.p12| pbcopy

and paste clipboard content into the textbox labeled Secret.

P12_PASSWORD

Just add password you have inputed when you were exporting that p.12 certificate.

PROVISION_PROFILES_BASE64

Go to your ios-build folder and do this:

base64 -i mobile-pp.tgz | pbcopy

and paste clipboard content into the textbox labeled Secret.

KEYCHAIN_PASSWORD

Do this:

pass -c temp/temp

and paste clipboard content into the textbox labeled Secret.

EXPORT_OPTIONS_PLIST

Go to your ios-build folder and do this:

base64 -i ExportOptions.plist| pbcopy

and paste clipboard content into the textbox labeled Secret.

Now you have everything you need in your secrets and you are ready to create to create your GitHub Action workflow for building iOS app.
To do this you have to create yml file. You will need to go to the root of your project and create .github folder. Inside that folder create new folder named workflows, and inside that folder you can create your yml file. I’ve called it build-ios-app.yml. Copy this code bellow and paste it into your yml file.

name: "Build iOS app"

on:
push:
branches:
- main

jobs:
build_with_signing:
runs-on: macos-latest
steps:
- name: check Xcode version
run: /usr/bin/xcodebuild -version
- name: checkout repository
uses: actions/checkout@v3
- name: Debug Workflow Variables
run: |
echo "CERTIFICATE_PATH: $CERTIFICATE_PATH"
echo "PP_PATH: $PP_PATH"
echo "KEYCHAIN_PATH: $KEYCHAIN_PATH"
echo "P12_PASSWORD: $P12_PASSWORD"
- name: Install the Apple certificate and provisioning profile
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
PROVISION_PROFILES_BASE64: ${{ secrets.PROVISION_PROFILES_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
PP_ARCHIVE=$RUNNER_TEMP/mobile_pp.tgz
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db

echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
echo -n "$PROVISION_PROFILES_BASE64" | base64 --decode -o $PP_ARCHIVE

security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH

echo "P12_PASSWORD: $P12_PASSWORD"
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH

mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
tar xzvf $PP_ARCHIVE -C $RUNNER_TEMP
for PROVISION in `ls $RUNNER_TEMP/*.mobileprovision`
do
UUID=`/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i $PROVISION)`
cp $PROVISION ~/Library/MobileDevice/Provisioning\ Profiles/$UUID.mobileprovision
done

security find-identity -v -p codesigning
ls -l ~/Library/MobileDevice/Provisioning\ Profiles

- uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'yarn'

- name: Clean workspace
run: |
git clean -ffdx
npm cache clean --force

- name: Clean Xcode Build
run: |
cd ios
xcodebuild clean -workspace your_app.xcworkspace -scheme your_app

- name: install yarn dependencies
run: |
cd ios
yarn install

- name: install Cocoapod dependencies
run: |
cd ios
pod repo update
pod install

- name: build archive
run: |
cd ios
xcodebuild -workspace your_app.xcworkspace \
-scheme "your_app" \
-sdk iphoneos \
-configuration Release \
-destination generic/platform=iOS \
-archivePath $RUNNER_TEMP/your_app.xcarchive \
archive

- name: export ipa
env:
EXPORT_OPTIONS_PLIST: ${{ secrets.EXPORT_OPTIONS_PLIST }}
run: |
EXPORT_OPTS_PATH=$RUNNER_TEMP/ExportOptions.plist
echo -n "$EXPORT_OPTIONS_PLIST" | base64 --decode -o $EXPORT_OPTS_PATH
xcodebuild -exportArchive -archivePath $RUNNER_TEMP/your_app.xcarchive -exportOptionsPlist $EXPORT_OPTS_PATH -exportPath $RUNNER_TEMP/build

- name: Upload application
uses: actions/upload-artifact@v3
with:
name: app
path: ${{ runner.temp }}/build
retention-days: 3

You will need to modify the “build archive” and “export ipa” command slightly so they are consistent with your scheme, configuration, etc.

And that it, you are all set. Every time you push something into your main branch this workflow will be triggered, app will be build and you will have IPA file at the end.

Building android app and getting APK file

Building android app and getting APK file is much easier then iOS. You don’t need any setup or any github secrets. You will just have to create yml file inside .github/workflows folder. I’ve called it build-android-app.yml
Copy this code bellow and paste it into your yml file.

name: "Build Android app"

on:
push:
branches:
- main

jobs:
build:
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Install Java
uses: actions/setup-java@v3
with:
java-version: 17
distribution: adopt
cache: gradle

- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'yarn'

- name: Run Yarn Install
run: |
npm i -g corepack
yarn install

- name: Build application
run: |
cd android
./gradlew assembleRelease

- name: Upload application
uses: actions/upload-artifact@v2
with:
name: app
path: android/app/build/outputs/apk/release/app-release.apk
retention-days: 3

And that it, you are all set. Every time you push something into your main branch this workflow will be triggered, app will be build and you will have APK file at the end. If you need AAB file instead of APK you just need to change assembleRelease to bundleRelease and change upload path to
android/app/build/outputs/bundle/release/app-release.aab.

Conclusion

To boost your mobile app development efficiency, implement workflows in both ‘staging’ and ‘main’ branches for robust testing and dependable production launches. Leveraging Firebase App Distribution simplifies access to the latest builds, facilitating better team collaboration and refining your app before its release on the App and Play Stores.

For comprehensive insights and practical implementation tips on uploading builds to Firebase App Distribution and App and Play stores, explore this link: https://medium.com/scaleuptech/how-to-upload-react-native-builds-with-github-actions-5f5ec08cc6b4.

--

--

Sanjin Sehic
ScaleUp
Editor for

Front-end developer with three years of experience, I specialize in building mobile applications using React Native and web applications using React.