Configuring your mobile app for CodePush
Configure the CodePush SDK in your React Native app to receive over-the-air updates. Both bare React Native and Expo projects are supported: see Configuring CodePush for bare React Native projects and Configuring CodePush for Expo apps.
The CodePush SDK is open-source and feedback is welcome.
Configuring CodePush for Expo appsClick to copy link
This guide is for projects which adopted Expo's Continuous Native Generation feature.
If you manually manage the native iOS and Android projects within your codebase (no Expo Prebuild), follow our bare React Native setup instructions instead.
-
Make sure your app's bundle ID and package name match the ones used while creating the apps on Bitrise. In
app.json, these are theios.bundleIdentifierandandroid.packagefields. -
Install the CodePush app SDK:
npm install @bitrise/code-push-sdk -
Add the Expo CodePush plugin to
app.json:{"plugins": [// ...existing plugins["@bitrise/code-push-sdk/expo",{"ios": {"CodePushDeploymentKey": "...","CodePushServerURL": "https://<workspace-slug>.codepush.bitrise.io"},"android": {"CodePushDeploymentKey": "...","CodePushServerURL": "https://<workspace-slug>.codepush.bitrise.io"}}]]}Deployment key: Copy the value from the Bitrise CodePush deployments page. You get the deployment key when creating the CodePush deployment on Bitrise.
Workspace slug: The server URL requires your Bitrise workspace slug: Identifying Workspaces and apps with their slugs.
Deployment keys are not secretsThese end up as plain string values in final app builds. They are not secrets, but they are unique to your workspace and your CodePush deployment setup.
-
Verify configuration by running
npx expo prebuild. You can manually verify the following generated files:ios/<projectname>/Info.plist: containsCodePushDeploymentKeyandCodePushServerURLentries.ios/<projectname>/AppDelegate.swift: contains theCodePushimport andReactNativeDelegate.bundleURL()method override.android/app/src/main/res/values/strings.xml: containsCodePushDeploymentKeyandCodePushServerURLentries.android/app/src/main/java/.../MainApplication.kt:jsBundleFilePathset toCodePush.getJSBundleFile().
-
Initialize the update check in your app's root component: Customizing the update lifecycle.
Configuring CodePush for bare React Native projectsClick to copy link
These instructions cover React Native's New Architecture. On older React Native versions, follow the SDK's iOS setup and Android setup guides instead — then come back to this page for the deployment key and server URL values.
-
Add the CodePush SDK to the project:
npm install @bitrise/code-push-sdk -
Set up the CodePush iOS SDK in your project: iOS setup.
-
Set up the CodePush Android SDK in your project: Android setup.
-
Initialize the update check in your app's root component: Customizing the update lifecycle.
iOS setupClick to copy link
-
Run
bundle exec pod installfrom theiosfolder to pick up the previously added CodePush SDK dependency. -
Update
ios/<projectname>/AppDelegate.swift:-
Add an import statement for CodePush headers:
import CodePush -
In
class ReactNativeDelegate, find the line which returns the bundle URL for production builds and replace it with a call to the CodePush SDK:override func bundleURL() -> URL? {#if DEBUGRCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")#else- Bundle.main.url(forResource: "main", withExtension: "jsbundle")+ CodePush.bundleURL()#endif}
Use CodePush to resolve the JS bundle location only in release builds. The
DEBUGpre-processor macro switches between the Metro packager in debug builds and CodePush in release builds, so Chrome Dev Tools and live reload keep working while you debug. -
-
Update
ios/<projectname>/Info.plistwith the CodePush deployment key and the CodePush server URL to let the CodePush runtime know which deployment it should query for updates against.<key>CodePushDeploymentKey</key><string></string><key>CodePushServerURL</key><string>https://<workspace-slug>.codepush.bitrise.io</string>Deployment key: Copy the value from the Bitrise CodePush deployments page. You get the deployment key when creating the CodePush deployment on Bitrise.
Workspace slug: The server URL requires your Bitrise workspace slug: Identifying Workspaces and apps with their slugs.
Deployment keys are not secretsThese end up as plain string values in final app builds. They are not secrets, but they are unique to your workspace and your CodePush deployment setup.
-
Optional: If your iOS minimum deployment target is lower than 15.5, you need to bump it to at least
15.5. Inios/Podfile, look for the lineplatform :ios, min_ios_version_supported. Change it toplatform :ios, '15.5'.
Android setupClick to copy link
-
Edit the app module's Gradle build script at
android/app/build.gradle. Add this at the end of the file as an additional build task definition:...apply from: "../../node_modules/@bitrise/code-push-sdk/android/codepush.gradle"... -
Update your Application class at
android/app/src/main/java/…/MainApplication.ktto hook into the CodePush runtime.+ import com.microsoft.codepush.react.CodePushclass MainApplication : Application(), ReactApplication {override val reactHost: ReactHost by lazy {getDefaultReactHost(context = applicationContext,packageList = PackageList(this).packages.apply {// Packages that cannot be autolinked yet can be added manually here, for example:// add(MyReactNativePackage())},+ // Set jsBundleFilePath to CodePush so CodePush resolves the JS bundle path+ // at startup (OTA update if available, fallback to bundled JS otherwise).+ jsBundleFilePath = CodePush.getJSBundleFile(),)}} -
In
android/app/src/main/res/values/strings.xml, add the CodePush deployment key and the CodePush server URL to let the CodePush runtime know which deployment it should query for updates against.<string name="CodePushDeploymentKey" translatable="false">...</string><string name="CodePushServerUrl" translatable="false">https://<workspace-slug>.codepush.bitrise.io</string>Deployment key: Copy the value from the Bitrise CodePush deployments page. You get the deployment key when creating the CodePush deployment on Bitrise.
Workspace slug: The server URL requires your Bitrise workspace slug: Identifying Workspaces and apps with their slugs.
Deployment keys are not secretsThese end up as plain string values in final app builds. They are not secrets, but they are unique to your workspace and your CodePush deployment setup.
Customizing the update lifecycleClick to copy link
After you complete the configuration steps, CodePush hooks into the app's lifecycle and can load an updated bundle instead of the one packaged into the app.
Customize when and how updates are installed by calling codePush.sync() from your app's root component. The SDK provides several options to customize the update experience.
The CodePush JS API reference lists all options and parameters.
You can set this up in several ways.
Silent sync on app startClick to copy link
The simplest, default behavior. Your app automatically downloads available updates and applies them the next time it restarts. This way, the entire update experience is silent to the end user, since they don't see any update dialog.
import { useEffect } from "react";
import codePush from "@bitrise/code-push-sdk";
function App() {
useEffect(() => {
// Fully silent update which keeps the app in
// sync with the server, without ever
// interrupting the end user
codePush.sync();
}, []);
return <YourAppContent />;
}
Silent sync every time the app resumesClick to copy link
Same as the previous, except the app checks for updates, or applies an update if one exists every time the app returns to the foreground.
import { useEffect } from "react";
import { AppState } from "react-native";
import codePush from "@bitrise/code-push-sdk";
function App() {
useEffect(() => {
const syncOptions = {
installMode: codePush.InstallMode.ON_NEXT_RESUME,
};
codePush.sync(syncOptions);
const subscription = AppState.addEventListener("change", (newState) => {
if (newState === "active") {
codePush.sync(syncOptions);
}
});
return () => subscription.remove();
}, []);
return <YourAppContent />;
}
InteractiveClick to copy link
When an update is available, prompt the end user for permission before downloading it, and then immediately apply the update. If an update sets the mandatory flag, the end user is still notified about the update, but they don't have the choice to ignore it.
import { useEffect } from "react";
import codePush from "@bitrise/code-push-sdk";
function App() {
useEffect(() => {
// Active update, which lets the end user know
// about each update, and displays it to them
// immediately after downloading it
codePush.sync({
updateDialog: true,
installMode: codePush.InstallMode.IMMEDIATE
});
}, []);
return <YourAppContent />;
}
Log/display progressClick to copy link
Pass the syncStatusChangedCallback and/or downloadProgressCallback arguments to sync to log the different stages of the process, or even display a progress bar to the user.
import { useEffect, useState } from "react";
import codePush from "@bitrise/code-push-sdk";
function App() {
const [status, setStatus] = useState(null);
useEffect(() => {
codePush.sync(
{},
(syncStatus) => setStatus(syncStatus),
({ receivedBytes, totalBytes }) => {
console.log(`${receivedBytes} of ${totalBytes} received.`);
}
);
}, []);
return <YourAppContent status={status} />;
}