Since 2019, GitHub supports CI/CD natively through its feature GitHub Actions. With its easy YAML configuration, huge community support and fair pricing, it has become a solution of choice for automating tests and deployments in Continuous Integration pipelines.

React Native does cooperate well with tools like Fastlane or Bitrise, which allows setting up near-zero-configuration CI/CD pipelines without too much hassle, but we can see that using GitHub for DevOps needs will help to reduce both decentralization and friction points, by focusing our whole mobile development workflow into one single platform.

Setting up our first CI job

First of all we need to create our .github/workflows/ folder which will serve as the point of entry for our CI jobs. For our first workflow file ci.yml we can keep it simple for now and create a job install-and-test that will install npm dependencies and run all tests against our React Native project every time we push to master.

name: Build Android and iOS on:

push:

branches:

- master jobs:

install-and-test:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v2

- name: Install npm dependencies

run: |

npm install

- name: Run tests

run: |

npm test

And that’s it! Right in the Actions tab on our project repository, the job will be run at every push, making sure we get a screen score at every step of the process.

Automating the Android build

Android release builds are signed with a keychain, so in order to make a release build with our CI setup, we need to pass a password to our signing logic before we try to compile our Android build. This is done through Secrets, a feature that we can use to store our keychain password that we will call KEYSTORE_PASSWORD and pass it on to our job.

Here we append our second job, that needs the first job install-and-test to execute and pass before wasting time trying to build it.

build-android:

needs: install-and-test

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v2

- name: Install npm dependencies

run: |

npm install

- name: Build Android Release

run: |

cd android && ./gradlew assembleRelease -PMYAPP_UPLOAD_STORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}' -PMYAPP_UPLOAD_KEY_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'

- name: Upload Artifact

uses: actions/upload-artifact@v1

with:

name: app-release.apk

path: android/app/build/outputs/apk/release/

The last part of that job will simply upload the generated apk file so it is retrieved through the GitHub interface!

Automating the iOS build

In order to make managing code signing and certificate easier, it is recommended to use a self-hosted runner that already manages our certificates and provisioning profiles. Other solutions might include using Fastlane or encrypting our signing files ourselves like in this article.

Creating an iOS build requires slightly different steps that Android too, as we need to install pod dependencies first.

The script below will output an ad-hoc build.

build-ios:

needs: install-and-test

runs-on: [self-hosted, macos]

steps:

- uses: actions/checkout@v2

- name: Install npm dependencies

run: |

npm install

- name: Install pod dependencies

run: |

cd ios && pod install

- name: Build app

run: |

xcodebuild -workspace myapp.xcworkspace -scheme myapp archive -archivePath myapp.xcarchive -allowProvisioningUpdates

xcodebuild -exportArchive -archivePath ./myapp.xcarchive -exportPath . -exportOptionsPlist myapp/Info.plist

mv myapp.ipa ../myapp.ipa

- name: Upload Artifact

uses: actions/upload-artifact@v1

with:

name: myapp.ipa

path: ios/build/

There we go, our React Native builds are automatically generated using GitHub’s own CI/CD workflow!