Easy Tutorial: CodePush-ify your React Native App

What is CodePush?

CodePush is a cloud service that enables Cordova and React Native developers to deploy mobile app updates directly to their users’ devices.

How does CodePush work in ReactNative?

A React Native app consists of JavaScript files and any accompanying images, which the packager bundles and distributes as part of a platform-specific binary (i.e., an .ipa or .apk file).

Once the app is released, updating the JavaScript code (e.g., fixing bugs or adding new features) or image assets, requires recompilation and redistribution of the entire binary, which includes, of course, any review time associated with the store(s) on which it is published.

The CodePush plugin helps get product enhancements to end users instantly, by keeping your JavaScript and images in sync with updates you release to the CodePush server. This way, your app gets the benefits of an offline mobile experience, as well as the “web-like” agility of side-loading updates as soon as they become available. It’s a win-win!

Note: Any changes to the product that touch native code (e.g. modifying your AppDelegate.m/MainActivity.java file, adding a new plugin) cannot be distributed via CodePush, and therefore must be updated via the appropriate store(s).

The operation is based on wrapping our app in a CodePush HOC (higher-order component) that is responsible for checking if there are new updates to our code in CodePush and reloading the app with the new changes.

React Native CodePush uses its own server to store a copy of each CodePush deployment and a control version in case a rollback is needed; this can be done almost instantly. All of this is managed through a user-friendly control panel provided by Microsoft, which not only allows you to control CodePush deployments but also conventional ones.

It also allows simultaneous testing of versions on a wide variety of devices and platforms.

The library has a wide variety of configuration parameters that, among other things, allow you to choose when to check for and download new versions of React Native CodePush for the app and also give you the ability to use events to determine when each of these processes has been completed. For example, you can notify the end-user that a new version will be installed the next time the app is restarted.

Setting up CodePush

Since CodePush is a cloud service from AppCenter, the first thing you need to do is to create an account in the App Center dashboard.

Next, create two apps, one per OS (iOS and Android).

CodePush React Native

Make sure to select release type production and platform React Native.

CodePush React Native

Once the app is created you’ll see some instructions to integrate App Center analytics and crash reporting tools which are NOT required to make CodePush work. But of course, you could install them if you want.

Next, continue with the CodePush setup. Go to Distribute => CodePush and then click on the Create standard deployments button. App Center will create two environments, Staging and Production, we will only use Production in this guide.

CodePush

As you can see in the image above, you must install appcenter-cli and login to AppCenter.

Once you have run the install command npm install -g appcenter-cli you will need to log in to AppCenter as follows:

  • Run appcenter login. This will open a browser and generate a new API token.
  • Copy the API token from the browser, and paste it into the command window.
  • The command window will display Logged in as {user-name}.
    Congratulations! You’ve successfully logged in and can run CLI commands.

Install the library in the ReactNative project

Once you’ve followed the general-purpose “getting started” instructions to set up your CodePush account, you can start CodePush-ifying your React Native app by running the following command from within your app’s root directory:

npm install --save react-native-code-push
or
yarn add react-native-code-push

iOS Setup

Plugin Installation and Configuration for React Native 0.60 version and above.

Run cd ios && pod install && cd ..  to install all the necessary CocoaPods dependencies.​

Open up the AppDelegate.m file, and add an import statement for the CodePush headers:

#import <CodePush/CodePush.h>

Find the following line of code, which sets the source URL for bridge for production releases:

return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

Replace it with this line:

return [CodePush bundleURL];

This change configures your app to always load the most recent version of your app’s JS bundle.

 NOTE: The bundleURL method assumes your app’s JS bundle is named main.jsbundle. If you have configured your app to use a different file name, simply call the bundleURLForResource: method (which assumes you’re using the .jsbundle extension) or bundleURLForResource:withExtension: method instead, in order to overwrite that default behavior.

Typically, you’ll only want to use CodePush to resolve the location of your JS bundle within release builds, and therefore, we recommend using the DEBUG pre-processor macro to dynamically switch between using the packager server and CodePush, depending on whether you are debugging or not.

This will make it much simpler to ensure you get the right behavior you want in production, while still being able to use the Chrome Dev Tools, live reload, etc. at debug-time.

Your  sourceURLForBridge  method should look like this:

– (NSURL*)sourceURLForBridge:(RCTBridge *)bridge
{
#if
DEBUG
 return[[RCTBundleURLProvider sharedSettings]
jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
 #else
  return [CodePush bundleURL];
#endif

}

 

Add the Deployment key to  Info.plist :

To let the CodePush runtime know which deployment it should query for updates against, open your app’s Info.plist file and add a new entry named CodePushDeploymentKey , whose value is the key of the deployment you want to configure this app against.

You can retrieve this value by running appcenter codepush deployment list -a <ownerName>/<appName> -k  and copying the value of the  Key  column which corresponds to the deployment you want to use.

In order to effectively make use of the  Staging and  Production deployments that were created along with your CodePush app, refer to the multi-deployment testing docs below before actually moving your app’s usage of CodePush into production.


Android Setup

Plugin Installation and Configuration for React Native 0.60 version and above.

In the android/settings.gradle file, make the following additions at the end of the file:


include ':app', ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, ‘../node_modules/react-native-code-push/android/app’)


In the android/app/build.gradle file, add the codepush.gradle file as an additional build task definition underneath react.gradle:


apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"


Update the MainApplication.java file to use CodePush via the following changes:


// 1. Import the plugin class.
import com.microsoft.codepush.react.CodePush;

public class MainApplication extends Application implements
ReactApplication
{

    private final ReactNativeHost mReactNativeHost = new
ReactNativeHost(this) {

        …
        // 2. Override the getJSBundleFile method in order to let
        // the CodePush runtime determine where to get the JS
       // bundle location from on each app start

        @Override
        protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();

        }
    };
}


Add the Deployment key to strings.xml:

To let the CodePush runtime know which deployment to query for updates, open your app’s strings.xml file and add a new string called CodePushDeploymentKey, whose value is the key of the deployment you want to configure this app against.

You can retrieve this value by running appcenter codepush deployment lista <ownerName>/<appName>k and copying the value of the Key column which corresponds to the deployment you want to use.

In order to effective use of the Staging and Production deployments that were created along with your CodePush app, refer to the multi-deployment testing docs below before actually moving your app’s usage of CodePush into production.

The strings.xml should look like this:

<resources>
    <string name="app_name">AppName</string>
    <string moduleConfig="true"
 
name="CodePushDeploymentKey">DeploymentKey</string>
</resources>


How to use CodePush in your ReactNative project


Modify JS Code

Wrap your root component with the codePush higher-order component (HOC):

For class component:

import codePush from "react-native-code-push";

class MyApp extends Component {
}

MyApp = codePush(MyApp);


For functional component:

import codePush from "react-native-code-push";

let MyApp: () => React$Node = () => {
}

MyApp = codePush(MyApp);


Run the app to make sure it’s working properly and pay attention to the metro server logs. You should be able to see that you are asking CodePush if there is any version to download.

Release a version to CodePush

Go to AppCenter -> Distribute -> CodePush

Find the release command and make sure you are using the right params.

The release command is:

appcenter codepush release-react -a <owner_name>/<app_name> -d Production


When the upload is completed, reload the AppCenter dashboard and make sure your release is there.


Now run the app again and look at the metro server logs, you should be able to download the version from CodePush. On the second session (close and open the app) this new downloaded version will be installed on the device and you will see your changes.

NOTE:
If you want to force the app to install the latest code push version in the same session in which the app downloads the bundle, you must mark the code push version as a required update in the App Center dashboard.

CodePush React Native

Sources

Authors

  • JP Mazza at Effectus Software
  • Bruno Pintos at Effectus Software

Read more articles