React Native OTA SDK Reference
Every method, install mode and no-update reason in the @otaupdate/react-native SDK.
Everything is exported from @otaupdate/react-native, both named and on the default export:
import OtaUpdate, { withOtaUpdate, useOtaUpdate, InstallMode, SyncStatus } from '@otaupdate/react-native';Functions and components
| Export | Purpose |
|---|---|
withOtaUpdate(App, options?) | Root-component wrapper. The whole integration for most apps. |
sync(options?) | Check → download → install. Concurrent calls share one run. Resolves to a SyncStatus; never throws. |
checkForUpdate(key?) | Just the check. Returns { update, reason }. |
notifyAppReady() | Confirms the running bundle. Required, or the update reverts on the next launch. |
restartApp(onlyIfPending?) | Reloads the JS bundle, applying a pending install now. |
getCurrentPackage() | The running OTA package, or null when running the bundle from the binary. |
clearUpdates() | Wipes every download and reverts to the bundle in the binary. Handy in development. |
startAutoSync(options?) | The launch/resume loop withOtaUpdate uses. Returns a teardown function. |
useOtaUpdate(options?) | Hook for update UI: { status, progress, available, error, isSyncing, check, update }. |
getConfig() | The resolved configuration: key, server, app version, channel, platform, running label. |
isNativeModuleAvailable | false in Expo Go and on web — every call would otherwise throw. |
OtaApiError | Thrown for server-side failures; carries an HTTP status. |
sync() options
| Option | Default | Meaning |
|---|---|---|
installMode | ON_NEXT_RESTART | When a normal update swaps in. |
mandatoryInstallMode | IMMEDIATE | When a release published with --mandatory swaps in. |
minimumBackgroundDuration | 0 | Seconds backgrounded before an ON_NEXT_RESUME install applies. |
onSyncStatusChange | — | Called with each SyncStatus as the run progresses. |
onDownloadProgress | — | Called with { receivedBytes, totalBytes } during download. |
shouldInstall | — | Return false to skip this update. Mandatory releases ignore it. |
deploymentKey | from native config | Override the key for this call. Rarely needed. |
withOtaUpdate() / startAutoSync() options
| Option | Default | Meaning |
|---|---|---|
checkOnAppStart | true | Sync once when the app starts. |
checkOnResume | true | Sync each time the app returns to the foreground. |
minimumSyncInterval | 60 | Minimum seconds between automatic syncs. |
sync | {} | The sync() options above, used for every automatic sync. |
Install modes
| Mode | When the new bundle loads |
|---|---|
InstallMode.ON_NEXT_RESTART | Default. The next cold start. Never interrupts. |
InstallMode.ON_NEXT_RESUME | Next foreground, after minimumBackgroundDuration seconds backgrounded. |
InstallMode.IMMEDIATE | Right away with a JS reload. Reserved for mandatory fixes. |
Sync statuses
SyncStatus values arrive through onSyncStatusChange and are what sync() resolves to. SyncStatus[value] gives you the name for logging.
| Status | Meaning |
|---|---|
CHECKING_FOR_UPDATE | Asking the server. |
AWAITING_USER_ACTION | Waiting on your shouldInstall callback. |
DOWNLOADING_PACKAGE | Fetching and verifying the bundle. |
INSTALLING_UPDATE | Applying it according to the install mode. |
UPDATE_INSTALLED | Done — live now, or on the next restart. |
UP_TO_DATE | Nothing applicable for this device. |
UPDATE_IGNORED | shouldInstall returned false. |
SYNC_IN_PROGRESS | Another sync was already running; this call joined it. |
UNKNOWN_ERROR | The run failed. The error is logged and reported; the app carries on. |
No-update reasons
checkForUpdate() returns a reason when there is nothing to install:
| Reason | Meaning |
|---|---|
up_to_date | Already on the newest applicable release. |
not_in_rollout | A newer release exists but this device is outside its rollout. |
no_release_for_runtime | No release on this channel targets this native app version. |
platform_disabled | This platform is switched off for the project. |
unknown_channel | The key resolved but the channel it names no longer exists. |
Native entry points
These are the calls your MainApplication and AppDelegate make — the Expo plugin wires them for you. Each resolves the bundle for this launch and advances the rollback state machine, so call them exactly where React Native asks for its bundle and nowhere else.
| Platform | Call | Notes |
|---|---|---|
| Android | OtaUpdate.getJSBundleFile(context) | Returns null for "use the bundle in the APK". A second overload takes the asset bundle name if yours is not index.android.bundle. |
| iOS | [OtaUpdate bundleURL] | bundleURLForResource:withExtension: covers a binary bundle that is not main.jsbundle; binaryBundleURL ignores downloads entirely. |
A broken OTA state cannot stop your app from starting
null whenever developer support is on, so a downloaded bundle never shadows your Metro live-reload in a debug build.Package shapes
| Type | Fields |
|---|---|
RemotePackage | label, packageHash, downloadUrl, size, isMandatory, description, targetBinaryVersion, rollout, isRollback, deployment, download(onProgress?) |
LocalPackage | label, packageHash, isMandatory, description, bundlePath, size, install(mode?, minimumBackgroundDuration?) |
CurrentPackage | label, packageHash, description, isMandatory, bundlePath, appVersion, isPending, isFirstRun |
label is the release number as a string — #14 — which is what the dashboard, ota status and your device logs all show.