Over the Air (OTA) Updates With React Native CodePush and GitHub Actions | by Aryella Lacerda | Jun, 2022

1*KTo1ShsunQ4v1AwEes peA

One way to address a classic mobile deployment problem in React Native… without having to go through the official app stores

After much debugging, you identify the source of a critical bug. Hurrah, it’s an easy fix! Unfortunately, you also identify that the bug started in version v1.0.0 and you’ve already shipped version v1.0.1 with the buggy code.

Now instead of a single problem, you’ve got a series of problems.

Releasing a new app version to the app stores can take time. You have a critical bug that’s impacting your users. You don’t want to wait 2–7 business days while the corrected version undergoes review, not if you don’t absolutely have to.

Even once you get approved and v1.0.2 is available in stores, users don’t tend to update their apps frequently. If you take a look at your analytics tool, there’s probably a graph that groups your users by the app version they’re using.

You’ll find it looks something like this:

It’s often the case that we have large portions of the user base using outdated versions of the app, as we see here. It could take weeks before most of the user base is using the corrected version. In the meantime, the bug will still be affecting users, even though you’ve technically already corrected it.

How do we start addressing this?

Well, in the case of React Native apps, deploying to CodePush is a viable option.

CodePush is an over-the-air (OTA) update service offered by Microsoft’s AppCenter. OTA updates are one of the big advantages of hybrid apps over native ones. They allow you to quickly deploy a new app version that bypasses the App Store and Play Store review processes.

Why Microsoft CodePush, you ask? Because I couldn’t find any other provider of a similar service for React Native. As of May 2022, distribution via CodePush is absolutely free.

Let’s take a look at how CodePush works in React Native, specifically.

Javascript thread vs. main (native) thread. javascript thread has javascript code, react library, bridge, which links to the main (native) thread, which has a bridge, native library, and native code

Every React Native app is split into two parts: native and JavaScript code. When you build your app, all your JavaScript code is compiled, and the and index.ios.bundle files are generated for Android and iOS, respectively. CodePush allows you to upload new bundles to AppCenter and then download them directly to your device.

There’s an important caveat here. It’s not possible to update native code via OTA. If native code has been changed or a new native library added, the update has to be deployed through the app stores as usual.

Yes. React Native CodePush’s docs include a section of Store Guideline Compliance which boils down to: it’s fine to update your JavaScript files via OTA so long as it doesn’t drastically change your app’s purpose or add/remove major functionality.

No, your users should always be encouraged to use the latest app version and you should keep releasing new versions. Some reasons for this include:

  • You’ll still need to go through the stores for native updates.
  • Frequently updated apps tend to be rewarded by the stores’ search algorithms. It would be a shame to lose that small advantage.
  • If you release the majority of your new features via CodePush, eventually your app will be changed enough that you might run into Guideline Compliance issues.
  • As you’ll see in the sections below, the CodePush release process isn’t always simple, so try to limit its use. If possible, use it only to correct bugs in versions that are still popular with users.
  1. The user downloads the app version vA.B.C from App Store or Google Play.
  2. Every time they start the app, CodePush will make an HTTPS request to AppCenter looking for new updates/fixes for vA.B.C.

If there is an update/fix:

  • The new code bundle (vA.B.C-fix.N) is downloaded. (The “-fix” suffix is arbitrary, it could be anything you’d like.)
  • The next time the user opens their app, the new version is installed.

If there isn’t an update/fix:

  • Nothing happens. The user continues using the app normally.

When developing in debug mode, you’ll even be able to see the CodePush logs in the Metro Bundler:

LOG  Running "your_mobile_app" with {"rootTag":1,"initialProps":{}}
LOG [CodePush] Checking for update.
LOG [CodePush] App is up to date.
1*lZYwE8MXk7AKqDX3dE9N A

Let’s go back to our example. You’ve located a bug that started in version v1.0.0 and you’ve already released version v1.0.1. How do we start correcting this? Well, notice that v1.0.0 and v1.0.1 have different source codes, which means that we need to correct the same bug twice and release three versions:

  • v1.0.0-fix.1: the code from v1.0.0 with bug fix, released to AppCenter. This code does not live on the main branch.
  • v1.0.1-fix.1: the code from v1.0.1 with bug fix, released to AppCenter. This code does not live on the main branch.
  • v1.0.2: the code from v1.0.1 with bug fix, released to Apple Store/Google Play. This is the code that will be merged to main.
1*7dVT98LTj zCf1Z6Reu0uQ

These are the steps that my team and I follow when we need to release anything via CodePush. We only distribute bug fixes via CodePush.

For each buggy version (v1.0.0, v1.0.1), do:

  • Check out the version with the bug and create a fix branch.
# git checkout tags/<tag> -b <branch>
git checkout tags/v1.0.0 -b fix/fix-a-critical-bug
# This is equivalent to:
git checkout tags/v1.0.0
git checkout -b fix/fix-a-critical-bug
  • Implement the bug fix. Make sure that you don’t have to install any native dependencies in the process.
  • Commit the bug fix.
  • Bump the app version by adding an appropriate suffix. I recommend something like fix, but this is arbitrary.
# In our case
v1.0.0 -> v1.0.0-fix.1
# Also possible, if you're fixing a fix version:
# v1.0.0-fix.1 -> v1.0.0-fix.2
  • Commit the version bump.
  • Push the new branch to the remote repository.
# git push --set-upstream origin <branch>
git push --set-upstream origin fix/fix-a-critical-bug

In the following section, we’ll detail a manually-triggered GitHub Actions workflow that deploys your releases to CodePush. It’s this workflow that I refer to in the step below.

  • Open your repo on GitHub and navigate to the Deploy Code Push GitHub Actions workflow.
  • Click the “Run workflow” button.
  • Choose the branch you were working on (fix/fix-a-critical-bug).
  • Click the green call-to-action “Run workflow” button.
  • Let the workflow finish and then delete the fix branch. The workflow creates a tag, so we don’t need to keep the branch.

This workflow makes use of app names you’ll define when you create your free AppCenter account and some keys and tokens that you’ll generate during the CodePush installation process. In this example, all the relevant keys and tokens have been defined in the repository’s secrets.

If you’re convinced CodePush is the right tool for you, head over to GitHub and install the React Native Code Push package.

Thanks for reading!

News Credit

%d bloggers like this: