メインコンテンツまでスキップ

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

Continuous Native Generation

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.

  1. 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 the ios.bundleIdentifier and android.package fields.

  2. Install the CodePush app SDK:

    npm install @bitrise/code-push-sdk
  3. 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 secrets

    These 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.

  4. Verify configuration by running npx expo prebuild. You can manually verify the following generated files:

    • ios/<projectname>/Info.plist: contains CodePushDeploymentKey and CodePushServerURL entries.
    • ios/<projectname>/AppDelegate.swift: contains the CodePush import and ReactNativeDelegate.bundleURL() method override.
    • android/app/src/main/res/values/strings.xml: contains CodePushDeploymentKey and CodePushServerURL entries.
    • android/app/src/main/java/.../MainApplication.kt: jsBundleFilePath set to CodePush.getJSBundleFile().
  5. 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.

  1. Add the CodePush SDK to the project:

    npm install @bitrise/code-push-sdk
  2. Set up the CodePush iOS SDK in your project: iOS setup.

  3. Set up the CodePush Android SDK in your project: Android setup.

  4. Initialize the update check in your app's root component: Customizing the update lifecycle.

iOS setupClick to copy link

  1. Run bundle exec pod install from the ios folder to pick up the previously added CodePush SDK dependency.

  2. Update ios/<projectname>/AppDelegate.swift:

    1. Add an import statement for CodePush headers:

      import CodePush
    2. In class ReactNativeDelegate, find the line which returns the bundle URL for production builds:

      Bundle.main.url(forResource: "main", withExtension: "jsbundle")
    3. Replace that with the following call to the CodePush SDK:

      CodePush.bundleURL()
    4. Your bundleURL method should look like this:

      override func bundleURL() -> URL? {
      #if DEBUG
      RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
      #else
      CodePush.bundleURL()
      #endif
      }

    Use CodePush to resolve the JS bundle location only in release builds. The DEBUG pre-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.

  3. Update ios/<projectname>/Info.plist with 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 secrets

    These 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.

  4. Optional: If your iOS minimum deployment target is lower than 15.5, you need to bump it to at least 15.5. In ios/Podfile, look for the line platform :ios, min_ios_version_supported. Change it to platform :ios, '15.5'.

Android setupClick to copy link

  1. 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"
    ...
  2. Update your Application class at android/app/src/main/java/…/MainApplication.kt to hook into the CodePush runtime.

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

    class 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())
    },
    // 2. 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(),
    )
    }
    }
  3. 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 secrets

    These 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.

API reference

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} />;
}