Usage of CodePush in React Native

Mahir Uslu
Innovance Blog
Published in
7 min readOct 15, 2023

Publishing the app to the stores sometimes is very exhausting because of the review duration, and sometimes the reviewer declines that version due to various causes. Besides this sometimes we make small mistakes or want small changes. And who wants to go through that process again and again every time? CodePush solves that problem entirely. Once you implement CodePush, you can update your app anytime, provided you don’t change the native codes.

Sounds good right? Let's learn how you implement CodePush.

“Live out of your imagination, not your history.” — Stephen Covey

What is CodePush?

CodePush, a service provided by Microsoft’s App Center, allows developers to push updates to React Native apps directly to users’ devices without going through the App Store or Google Play Store. This article will delve into the usage of CodePush in React Native, exploring its benefits, implementation, and best practices.

The Benefits of Using CodePush

  1. Seamless Updates: CodePush enables you to deliver updates instantly, eliminating the need for users to wait for app store approvals and downloads. This means quicker bug fixes and feature rollouts, resulting in a more satisfying user experience.
  2. Reduce Release Cycle: CodePush allows you to skip the lengthy release cycle required by app stores. You can push updates as frequently as needed, making addressing issues promptly and maintaining a cutting-edge app easier.
  3. A/B Testing: Implement A/B testing by pushing updates to a subset of users, enabling you to gather feedback and assess the performance of new features before a full-scale release.
  4. Optimized Rollouts: Gradually roll out updates to users in stages, ensuring that any unforeseen issues can be addressed before impacting the entire user base.

To start using CodePush in your React Native project, follow these steps:

First, you need to install CodePush to project:

yarn add react-native-code-push

After that, you need to set up the project in Microsoft’s app center.

  • Go to the app center
  • Sign up or sign in. You’ll see the following screen.
  • Click Add New App, a drawer will appear at the right of the screen.
  • Give a name to the app. You have to create two apps both iOS and Android. You can give names in this context.
  • Select OS and Platform. In this case; the platform is RN.
  • A guide will appear at this point.
  • You’ll need the app secret, save it for later.

Now, you need to set up OS’s

iOS;

  1. Run cd ios && pod install && cd .. to install all the necessary CocoaPods dependencies.​
  2. Open up the AppDelegate.m file, and add an import statement for the CodePush headers:
#import <CodePush/CodePush.h>

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

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge

4. Replace the method with this:

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

5. Add the Deployment key to Info.plist:


<key>CodePushDeploymentKey</key>
<string>[YOUR_IOS_CODE_PUSH_KEY]</string>

ANDROID;

  1. In your 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')

2. In your android/app/build.gradle file, add the codepush.gradle file as an additional build task definition to the end of the file:

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

3. 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();
}
};
}

4. Add the Deployment key build.gradle;

def codePushKey = safeExtGet("YOUR_ANDROID_CODE_PUSH_KEY")

or

Add the Deployment key to Strings.xml

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

Setups are complete. Now you need a screen to show the user download status.

  1. Create a functional component

Get props for showing the status of CodePush and progress to the user. You’ll get these with a hook from the second step.

const CodePushLoading: FC<CodePushLoadingProps> = ({
header = 'Downloading',
subHeader = 'general_codePush_codePush_text',
progress = '0%',
}) => {
return (
<View>
<Text label={header} variant={'title3'} />
<Space size={12} />
<Text label={subHeader} variant={'body6'} />
<Space size={24} />
<ActivityIndicator color={colors.darkGrey} size="large" />
<Space size={24} />
<Text label={progress} variant={'body4'} />
</View>
);
};

export default CodePushLoading;

2. Create a hook to control CodePush

In this hook you’ll return two parameters; message and progress. You can see them below;

For the message you’ll control SyncStatus to show the user current status

import { useEffect, useState } from 'react';

import SplashScreen from 'react-native-bootsplash';
import codePush, { DownloadProgress } from 'react-native-code-push';

interface UseCodePushReturn {
syncMessage?: string;
progress?: string;
}

const useCodePush = (isLoading: boolean): UseCodePushReturn => {
const [syncMessage, setSyncMessage] = useState<string>();
const [progress, setProgress] = useState<string>();

const syncStatusChangedCallback = (syncStatus: codePush.SyncStatus) => {
switch (syncStatus) {
case codePush.SyncStatus.CHECKING_FOR_UPDATE:
setSyncMessage('Checking for update...');
break;
case codePush.SyncStatus.DOWNLOADING_PACKAGE:
setSyncMessage('Downloading update...');
break;
case codePush.SyncStatus.AWAITING_USER_ACTION:
setSyncMessage('User waiting...');
break;
case codePush.SyncStatus.INSTALLING_UPDATE:
setSyncMessage('Loading update...');
break;
case codePush.SyncStatus.UP_TO_DATE:
setSyncMessage('The app is up to date...');
break;
case codePush.SyncStatus.UPDATE_IGNORED:
setSyncMessage('Update canceled by user...');
break;
case codePush.SyncStatus.UPDATE_INSTALLED:
setSyncMessage('Update installed, Application restarting...');
break;
case codePush.SyncStatus.UNKNOWN_ERROR:
setSyncMessage('An error occurred during the update...');
break;
default:
setSyncMessage(undefined);
break;
}
};

const downloadProgressCallback = ({ receivedBytes, totalBytes }: DownloadProgress) => {
const currentProgress = Math.round((receivedBytes / totalBytes) * 100);
setProgress(`${currentProgress} %`);
};

useEffect(() => {
if (!isLoading) {
SplashScreen.hide({ fade: true, duration: 360 });
if (!__DEV__) {
codePush.notifyAppReady();
codePush.checkForUpdate().then(update => {
if (update) {
codePush.sync(
{ installMode: codePush.InstallMode.IMMEDIATE },
syncStatusChangedCallback,
downloadProgressCallback,
);
}
});
}
}
}, [isLoading]);

return {
syncMessage,
progress,
};
};

export default useCodePush;

3. After that you need to call in the main file of the application. App.ts

First, call the hook you just wrote.


const { progress, syncMessage } = useCodePush(isLocalizationLoading || isAppUpdateLoading);

then call “CodePushLoading.tsx” conditionally;

progress || syncMessage ? (
<CodePushLoading progress={progress} subHeader={syncMessage} />
) : (
//Example
<Navigation />
)

That’s it. You just completed to setup of CodePush.

Now let’s learn how to send updates to CodePush;

In the left panel of the app center, click “CodePush ” link under the “Distribute”

Create the app. At the right top “Staging” is selected. If you want to change to “Production” as you need.

After all your changes run following script in the terminal.

appcenter codepush release-react -a mahir/testIos -d Production -m

That’s it. Your js bundle is sent to the app center cloud. And will serve users immediately because you use “-m” flag, that’s means mandatory. Users will download updates on the next launch.

P.S. The versions are crucial. If they are not matched with the “Target Version” users can’t see downloads

Next Steps…

What is the Best Practices Of CodePush

  1. Test Thoroughly: Even though CodePush simplifies the update process, thorough testing is essential. Always test updates in a staging environment to catch potential issues before they reach your users.
  2. Keep CodePush Keys Secure: Your App Center API key should be kept secure to prevent unauthorized updates. Do not hardcode it in your app; instead, use environment variables or a secure storage solution.
  3. Versioning: Maintain a clear versioning strategy for your updates to ensure that users receive the correct releases.
  4. Communicate with Users: Notify users when updates are available and explain the benefits of updating to encourage them to do so.

Conclusion

In today’s fast-paced development world, ensuring that our applications are up-to-date without causing disruption to our users is paramount. CodePush provides an invaluable tool for React Native developersto achieve this goal. Through its seamless integration and ability to deliver updates on-the-fly, it streamlines the app updating process, providing a smoother experience for both developers and users alike. As we’ve explored in this guide, implementing CodePush is straightforward, and the benefits it offers in terms of flexibility and responsiveness are undeniable. Whether you’re a seasoned developer or just starting out with React Native, consider integrating CodePush into your workflow. The convenience it brings could revolutionize how you deliver updates and maintain your application. Remember in the realm of mobile applications, user experience is king — and a tool that can enhance that experience is worth its weight in gold.

Thank you for your interest, and if you like the article don’t forget to follow me.

--

--