HotupdaterHot Updater
React Native API

wrap

`HotUpdater.wrap` checks for updates at the entry point, and if there is a bundle to update, it downloads the bundle and applies the update strategy.

Usage

Important: HotUpdater.wrap is required for all apps. It enables automatic crash detection and rollback. All HotUpdater methods will throw an error if wrap is not used.

HotUpdater.wrap supports two usage patterns:

Option 1: With Automatic Updates

Use this for apps that want automatic OTA updates. This is the standard approach with full update management.

import { HotUpdater } from "@hot-updater/react-native";
import { View, Text } from "react-native";

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default HotUpdater.wrap({ 
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion", // or "fingerprint"
  updateMode: "auto",
  // If you need to send request headers, you can use the `requestHeaders` option.
  requestHeaders: {
    "Authorization": "Bearer <your-access-token>",
  },
})(App);

Option 2: Manual Updates Only (Custom Flow)

Use this for apps with custom update logic.

import { HotUpdater } from "@hot-updater/react-native";
import { View, Text } from "react-native";

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default HotUpdater.wrap({ 
  baseURL: "<your-update-server-url>",
  updateMode: "manual",
})(App);

Then use checkForUpdate or updateBundle manually when needed:

import { HotUpdater } from "@hot-updater/react-native";
import { useEffect } from "react";

function App() {
  useEffect(() => {
    const checkUpdate = async () => {
      const updateInfo = await HotUpdater.checkForUpdate({
        updateStrategy: "appVersion", // Required: specify update strategy
        requestHeaders: {
          Authorization: "Bearer <your-access-token>",
        },
      });

      if (!updateInfo) {
        console.log("No update found");
        return;
      }

      await updateInfo.updateBundle();
      if (updateInfo.shouldForceUpdate) {
        await HotUpdater.reload();
      }
    };

    checkUpdate();
  }, []);

  // ... your app
}

export default HotUpdater.wrap({
  baseURL: "<your-update-server-url>",
  updateMode: "manual",
  requestHeaders: {
    "Authorization": "Bearer <your-access-token>",
  },
})(App);

Configuration Reference

HotUpdater.wrap accepts different options depending on the update mode.

Common Options

Available in both automatic and manual modes:

OptionTypeRequiredDescription
baseURLstringYes*Your update server URL (standard approach)
resolverHotUpdaterResolverYes*Custom network operations (advanced)
requestHeadersRecord<string, string>NoCustom HTTP headers for update requests
requestTimeoutnumberNoRequest timeout in milliseconds (default: 5000)

*Either baseURL or resolver must be provided (mutually exclusive)

Automatic Mode Options

The following options are only available when updateMode: "auto" or omitted (automatic mode is the default):

OptionTypeRequiredDescription
updateStrategy"appVersion" | "fingerprint"YesUpdate detection strategy
requestHeadersRecord<string, string>NoCustom HTTP headers for update requests
requestTimeoutnumberNoRequest timeout in milliseconds (default: 5000)
fallbackComponentReact.FC<{status, progress, message}>NoUI component shown during updates
onProgress(progress: number) => voidNoCallback fired during bundle download (0-1)
reloadOnForceUpdatebooleanNoAuto-reload on force updates (default: true)
onUpdateProcessCompleted(response) => voidNoCallback when update process completes
onError(error) => voidNoError handler for update failures

fallbackComponent

During an update check, access to the entry point is temporarily blocked while communicating with the server.

  • If the update is force update, the entry point remains blocked, and the progress updates as the bundle downloads.
  • If not force update, the entry point is only blocked during the update check.

Without a fallbackComponent, the bundle downloads without blocking the screen.

Props:

  • progress: Download progress (0-1, e.g., for a progress bar)
  • status: Update state (CHECK_FOR_UPDATE or UPDATING)
  • message: Optional message from the server

Example:

import { HotUpdater } from "@hot-updater/react-native";
import { View, Text, Modal } from "react-native";

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default HotUpdater.wrap({ 
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion", // or "fingerprint"
  updateMode: "auto",
  fallbackComponent: ({ progress, status, message }) => (
      <View
        style={{
          flex: 1,
          padding: 20,
          borderRadius: 10,
          justifyContent: "center",
          alignItems: "center",
          backgroundColor: "rgba(0, 0, 0, 0.5)",
        }}
      >
        {/* You can put a splash image here. */}

        <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
          {status === "UPDATING" ? "Updating..." : "Checking for Update..."}
        </Text>
        {message && (
          <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
            {message}
          </Text>
        )}
        {progress > 0 ? (
          <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
            {Math.round(progress * 100)}%
          </Text>
        ) : null}
      </View>
    ),
  })(App);

reloadOnForceUpdate

When a force update bundle is downloaded, the app will automatically reload. If false, shouldForceUpdate will be returned as true in onUpdateProcessCompleted but the app won't reload. Default is true.

Example with auto-reload:

import { HotUpdater } from "@hot-updater/react-native";
import { View, Text } from "react-native";

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default HotUpdater.wrap({
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion", // or "fingerprint"
  updateMode: "auto",
  // If you need to send request headers, you can use the `requestHeaders` option.
  requestHeaders: {
    "Authorization": "Bearer <your-access-token>",
  },
  reloadOnForceUpdate: true, // Automatically reload the app on force updates
})(App);

Example without auto-reload:

import { HotUpdater } from "@hot-updater/react-native";
import { View, Text } from "react-native";

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default HotUpdater.wrap({
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion", // or "fingerprint"
  updateMode: "auto",
  // If you need to send request headers, you can use the `requestHeaders` option.
  requestHeaders: {
    "Authorization": "Bearer <your-access-token>",
  },
  reloadOnForceUpdate: false, // The app won't reload on force updates
  onUpdateProcessCompleted: ({ status, shouldForceUpdate, id, message }) => {
    console.log("Bundle updated:", status, shouldForceUpdate, id, message);
    if (shouldForceUpdate) {
      await HotUpdater.reload();
    }
  },
})(App);

onUpdateProcessCompleted

Allows you to perform additional actions after the update process is completed.

Callback Arguments:

PropertyTypeDescription
status"ROLLBACK" | "UPDATE" | "UP_TO_DATE"The status of the update process
shouldForceUpdatebooleanWhether the update process is forced
idstringThe ID of the bundle to update
messagestringThe message of the update process
import { HotUpdater } from "@hot-updater/react-native";
import { View, Text } from "react-native";

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default HotUpdater.wrap({
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion", // or "fingerprint"
  updateMode: "auto",
  // If you need to send request headers, you can use the `requestHeaders` option.
  requestHeaders: {
    "Authorization": "Bearer <your-access-token>",
  },
  onUpdateProcessCompleted: ({ status, shouldForceUpdate, id, message }) => {
    console.log("Bundle updated:", status, shouldForceUpdate, id, message);
  },

  // If you need to show the progress while downloading the new bundle, you can use the `onProgress` option.
  onProgress: (progress) => {
    console.log("Bundle downloading progress:", progress);
  },
})(App);

onError

Handles all errors during the update process.

Example:

import { HotUpdater } from "@hot-updater/react-native";
import { Alert } from "react-native";

export default HotUpdater.wrap({
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion",
  updateMode: "auto",
  onError: (error) => { 
    // Handle other errors
    console.error("Update error:", error);
  },
})(App);

How It Works

When you use HotUpdater.wrap with automatic updates, it constructs the appropriate endpoint URL based on the updateStrategy:

  • For updateStrategy: "appVersion": GET {baseURL}/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId
  • For updateStrategy: "fingerprint": GET {baseURL}/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId

The function automatically appends the correct path and parameters to your baseURL.

Advanced: Custom Resolver

For advanced use cases where you need full control over network operations - such as implementing a custom server, using GraphQL, or complex authentication flows - you can use a custom resolver instead of baseURL.

import { HotUpdater } from "@hot-updater/react-native";
import { useEffect } from "react";

function App() {
  useEffect(() => {
    const checkUpdate = async () => {
      // When you call HotUpdater.checkForUpdate(),
      // it will use the resolver.checkUpdate() defined below
      const updateInfo = await HotUpdater.checkForUpdate({
        updateStrategy: "appVersion",
      });

      if (updateInfo) {
        await updateInfo.updateBundle();
        if (updateInfo.shouldForceUpdate) {
          await HotUpdater.reload();
        }
      }
    };

    checkUpdate();
  }, []);
 
  return ...
}

export default HotUpdater.wrap({
  resolver: { 
    // Override the default update check logic
    checkUpdate: async (params) => { 
      // Custom network logic - GraphQL, custom API, etc.
      const response = await fetch(`https://custom-api.com/check`, { 
        method: 'POST', 
        body: JSON.stringify({ 
          platform: params.platform, 
          appVersion: params.appVersion, 
          bundleId: params.bundleId, 
        }), 
        headers: params.requestHeaders, 
      }); 
      if (!response.ok) return null; 
      return response.json(); 
    }, 
  }, 
  updateMode: "manual", // or "auto"
})(App);

Note: The resolver option is mutually exclusive with baseURL. Using resolver.checkUpdate() overrides the default update check implementation.

Flag Behavior

Update TypeWhen AppliedHow to Enable
DefaultDownloads the update bundle in the background and applies it when the user restarts the app.Default setting
Force UpdateDownloads the update bundle and applies it immediately.Use the --force-update flag or console.