wrap
`HotUpdater.wrap` stages standard updates for the next app start and reloads force updates by default.
Usage
Important: Configure Hot Updater with either
HotUpdater.wraporHotUpdater.initbefore calling update APIs. This enables automatic crash detection and rollback. Update methods will throw an error if neither API is used.
HotUpdater.wrap configures automatic updates. The automatic mode is the
default, so updateMode is no longer needed.
A standard update is prepared and staged without reloading the React Native
runtime currently in use. Once staging finishes successfully, it becomes active
the next time that runtime starts, normally on the next cold app launch. In the
automatic HotUpdater.wrap flow, responses with shouldForceUpdate: true,
including bundle-changing server-directed rollbacks, prepare the selected
transition and then reload by default. Set reloadOnForceUpdate: false when the
current session must remain uninterrupted.
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"
// If you need to send request headers, you can use the `requestHeaders` option.
requestHeaders: {
"Authorization": "Bearer <your-access-token>",
},
})(App);Manual Updates
Use HotUpdater.init for manual update flows.
Initialize once with HotUpdater.init, export your root component directly,
then call checkForUpdate or updateBundle when needed.
import { HotUpdater } from "@hot-updater/react-native";
HotUpdater.init({
baseURL: "<your-update-server-url>",
});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
}
HotUpdater.init({
baseURL: "<your-update-server-url>",
requestHeaders: {
"Authorization": "Bearer <your-access-token>",
},
});
export default App;Configuration Reference
HotUpdater.wrap accepts automatic update options.
Common Options
| Option | Type | Required | Description |
|---|---|---|---|
baseURL | string | () => string | Promise<string> | Yes* | Your update server URL (standard approach) |
resolver | HotUpdaterResolver | Yes* | Custom network operations (advanced) |
requestHeaders | Record<string, string> | No | Custom HTTP headers for update requests |
requestTimeout | number | No | Request timeout in milliseconds (default: 5000) |
onNotifyAppReady | (result) => void | No | Callback invoked after native app-ready state is read |
*Either baseURL or resolver must be provided (mutually exclusive)
Automatic Mode Options
The following options are available in automatic mode:
| Option | Type | Required | Description |
|---|---|---|---|
updateStrategy | "appVersion" | "fingerprint" | Yes | Update detection strategy |
requestHeaders | Record<string, string> | No | Custom HTTP headers for update requests |
requestTimeout | number | No | Request timeout in milliseconds (default: 5000) |
fallbackComponent | React.FC<HotUpdaterFallbackComponentProps> | No | UI component shown during updates |
onProgress | (progress: number) => void | No | Callback fired during bundle download (0-1) |
reloadOnForceUpdate | boolean | No | Auto-reload on force updates (default: true) |
onUpdateProcessCompleted | (response) => void | No | Callback when update process completes |
onError | (error) => void | No | Error 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_UPDATEorUPDATING)message: Optional server message (string | null)
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"
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 the automatic HotUpdater.wrap flow receives an update with
shouldForceUpdate: true, it prepares the selected transition and reloads the
app by default. Bundle-changing server-directed rollbacks also use this path.
If set to false, the current React Native runtime keeps running and the staged
update becomes active on the next runtime start or after a later explicit
HotUpdater.reload() call.
This option only controls the automatic HotUpdater.wrap flow.
updateBundle() never reloads the app by itself.
The actual reload behavior follows HotUpdater.setReloadBehavior().
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"
// 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"
// If you need to send request headers, you can use the `requestHeaders` option.
requestHeaders: {
"Authorization": "Bearer <your-access-token>",
},
reloadOnForceUpdate: false, // Keep the current session running
})(App);onUpdateProcessCompleted
Reports when automatic update handling has finished from the wrapper's perspective.
For a non-force update, the automatic flow invokes this callback after starting the non-blocking download, not after the download finishes. Do not use it as a download-readiness signal.
Callback Arguments:
| Property | Type | Description |
|---|---|---|
status | "ROLLBACK" | "UPDATE" | "UP_TO_DATE" | The status of the update process |
shouldForceUpdate | boolean | Whether the update process is forced |
id | string | The ID of the bundle to update |
message | string | null | The optional 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"
// 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",
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";
import YourApp from "./YourApp";
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 <YourApp />;
}
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();
},
},
updateStrategy: "appVersion",
})(App);Note: The
resolveroption is mutually exclusive withbaseURL. Usingresolver.checkUpdate()overrides the default update check implementation.
Flag Behavior
| Update Response | Runtime Behavior | How to Enable |
|---|---|---|
shouldForceUpdate: false | Stages the selected bundle without reloading the current runtime; it becomes active on the next runtime start. | Default setting |
shouldForceUpdate: true | HotUpdater.wrap reloads after preparing the selected transition; reloadOnForceUpdate: false defers it to a later start. | Use --force-update or the console; bundle-changing rollbacks also return it. |