CodePush Update Strategies for a React Native App

Take advantage of advanced CodePush options to get your updates to users faster

Manu Rana
3 min readFeb 21, 2020
Photo by Gilles Lambert on Unsplash

One of the biggest advantages that React Native provides over pure iOS or Android implementations is the ability to push an update over-the-air (OTA) without having to go through the onerous and time-consuming process of publishing in the respective app stores.

CodePush (by Microsoft) is the service that makes OTA updates possible. It works by updating the javascript bundle incrementally. It’s pretty clever, and you can read about it in the wonderful docs.

A CodePush update requires an app restart to complete, which can be disruptive to the user’s experience. We want to figure out a way to present our CodePush updates to the user as soon as possible while minimizing the effect of this restart. There are two parameters we can play with to achieve the balance we want: checkFrequency and installMode.

CodePush defaults to the following config :

{
checkFrequency: codePush.CheckFrequency.ON_APP_START,
installMode: codePush.InstallMode.ON_NEXT_RESTART,
}

From the docs:

Your app will automatically download available updates, and apply them the next time the app restarts (like the OS or end user killed it, or the device was restarted). This way, the entire update experience is “silent” to the end user, since they don’t see any update prompt and/or “synthetic” app restarts.

Although optimized for user experience, this is not guaranteed to deliver updates quickly because apps can hang around in the background for months before being restarted. To change this, we set the checkFrequency to ON_APP_RESUME and installMode to ON_NEXT_RESUME or ON_NEXT_SUSPEND, as well as the parameterminimumBackgroundDurationto 30 minutes. All these are documented here.

{
checkFrequency: codePush.CheckFrequency.ON_APP_RESUME,
installMode: codePush.InstallMode.ON_NEXT_RESUME,
minimumBackgroundDuration: 30*60 // 30 minutes
}

The parameter minimumBackgroundDuration (used in combination with ON_NEXT_RESUME or ON_NEXT_SUSPEND) is very interesting and important because it ensures that “user context isn't lost unless the app suspension is long enough to not matter.” An example would be a user switching apps in the middle of a transaction to check an OTP or to answer a phone call. We don’t want this user to have to start from the home screen again (which is what will happen if the app restarts for applying an update).

Advanced: Installing Updates Immediately

But we have still not ensured that the user has the latest updates every time she interacts with the app. If that is important for us, we will have to go one step further. Let us configure the updates to be installed immediately (if any update is available).

{
checkFrequency: codePush.CheckFrequency.ON_APP_RESUME,
installMode: codePush.InstallMode.IMMEDIATE,
}

But wait, now we have lost the ability to set minimumBackgroundDuration (this ONLY works with installMode set to ON_NEXT_RESUME or ON_NEXT_SUSPEND). And we just discovered how important this is for good user experience.

So what do we do?

First, we will have to configure CodePush to let us check for updates manually, so we can do it programmatically while respecting the minimumBackgroundDuration (or a similar parameter that we will now have to manually maintain).

{
checkFrequency: codePush.CheckFrequency.MANUAL,
}

We also configure a variable in our code (let us call it lastBackgroundedTime) which keeps a track of when the app was last backgrounded. We will maintain it as a state variable in the main app class.

We have to hook into the AppState API provided by React Native (which can tell us when the app is being foregrounded or backgrounded) for two things:

  1. To record the lastBackgroundedTime
  2. To manually check for CodePush update on app resume, but only if the app was backgrounded more than the minimumBackgroundDuration.

We can use the sync method provided by CodePush to programmatically check for updates (and install them immediately). This is an asynchronous call.

await codePush.sync(
{
installMode: codePush.InstallMode.IMMEDIATE,
}
);

We don’t want the user to interact with the app while the check (and update, if necessary) is happening. We can use a modal or splash screen to ensure this.

We can monitor the status (and display it to the user the same modal/splash screen) by using the syncStatusChangedCallback and downloadProgressCallback on the sync method. Example here.

Or we can use the codePushStatusDidChange and codePushDownloadDidProgress event hooks while configuring CodePush in the app. This is documented here

The app will automatically restart if and when a CodePush update is successfully installed.

Let's take a look at how this will look like in code.

sample index.js for your app

--

--