Documentation

SDK API reference

Look up public exports, defaults, hooks, check results and error contracts.

Updated 2026-09-14

On this page

Complete the minimal integration first. Use this page to look up options; you do not need every option. Reuse one client instance for reporting and configuration.

Overview

All public APIs of the Pakta SDK (npm package rn-update) are exported from the package entry. Five groups:

  • The Pakta client class and ClientOptions

  • The UpdateProvider (alias PaktaProvider) React integration

  • The useUpdate() / useUpdateProgress() / usePakta() hooks

  • Update metadata and crash-report correlation

  • The UpdateError type and the event model

Client class

tsx
import { Pakta } from 'rn-update';

const client = new Pakta({
  appKey: '<your appKey>',
  updateStrategy: 'silentAndLater',
});

// Update configuration at runtime (idempotent merge; re-renders the Provider)
client.setOptions({ checkStrategy: 'onAppResume' });

// Manually report a JS exception (global ErrorUtils is chained automatically)
client.captureException(error, { context: 'checkout' });

ClientOptions

FieldTypeDefaultDescription
appKeystringrequiredPlatform appKey assigned by the console
server{ main: string[]; queryUrls?: string[] }official endpointsSelf-hosted service address and endpoint discovery list
updateStrategysee below'alertUpdateAndIgnoreError'Prompt and activation strategy
checkStrategy'onAppStart' | 'onAppResume' | 'both' | null'both'Check timing; null disables JS auto-check
autoMarkSuccessbooleantrueAuto-confirm the running version as healthy
autoMarkSuccessDelayMsnumber1000Auto-confirm delay; raise when critical modules load late
healthCheck() => boolean | Promise<boolean>Health gate before confirming; false skips this launch
maxRetriesnumber3Download retry count
logger({ type, data }) => voidUpdate event logger
locale'zh' | 'en''zh'Built-in prompt language
debugbooleanfalseVerbose internal logs
throwErrorbooleanfalseThrow update errors to JS
testChannelbooleantrueHonor test QR codes/deep links; use false in production
beforeCheckUpdate / afterCheckUpdatehooksAround every check
beforeDownloadUpdate / afterDownloadUpdatehooksAround every download
beforeReload(ctx: { type: 'switchVersion' | 'restartApp' }) => …Before reload
onPackageExpiredhookOverrides the expired-package default behavior
disableTelemetrybooleanfalseDisable client telemetry and JS error transport
disableErrorReportingbooleanfalseDisable JS error reporting only

updateStrategy values: 'silentAndNow', 'silentAndLater', 'alertUpdateAndIgnoreError', 'alwaysAlert'.

React integration

tsx
import { Pakta, UpdateProvider, PaktaProvider, useUpdate, usePakta, useUpdateProgress } from 'rn-update';
  • UpdateProvider / PaktaProvider (alias) — takes a client prop; mounting a second provider in the same process throws.

  • useUpdate() — update state and actions (below).

  • useUpdateProgress() — isolated download progress { hash, received, total, progress? }.

  • usePakta() — an alias of useUpdate(), returning the same state and actions; access the instance through useUpdate().client.

UpdateContextValue returned by useUpdate():

MemberDescription
updateInfoLast CheckResult
lastErrorLast error
currentHash / packageVersionActive update hash and native package version
currentVersionInfo{ name?, description?, metaInfo? }
checkUpdate(params?)Manual check
downloadUpdate(info?)Download
switchVersion(info?)Switch to the downloaded version now (JS reload)
switchVersionLater(info?)Apply on next launch
markSuccess()Confirm the current version as healthy
restartApp()Restart the app
resetToPackagedBundle(options?)Return to the bundled JS
downloadAndInstallApk(url)Download and install a native upgrade APK (expired package)
parseTestQrCode(code)Parse a test QR code / deep link
dismissError()Clear lastError

CheckResult and version info

ts
interface CheckResult {
  upToDate?: boolean;      // already latest
  update?: boolean;        // update available
  expired?: boolean;       // native package expired; downloadUrl points to the new binary
  paused?: 'app' | 'package'; // application or native package paused
  downloadUrl?: string;    // expired-binary download address
  bundleStatus?: 'matched' | 'rebuiltSameJs' | 'unknownBundle';
  name?: string;           // version name
  hash?: string;           // version hash
  description?: string;    // version description
  metaInfo?: string;       // custom metadata (JSON string)
  config?: { rollout?: Record<string, number>; forceBoot?: boolean };
  pdiff?: string;          // precise differential package
  diff?: string;           // generic differential package
  full?: string;           // full package
}

bundleStatus reflects native registration: matched — full match; rebuiltSameJs — same JS fingerprint but a different build time (full package only); unknownBundle — unregistered fingerprint (kept on the current version under strict channel delivery).

Metadata and crash correlation

tsx
import * as Sentry from '@sentry/react-native';
import { attachToSentry, getUpdateMetadata } from 'rn-update';

// Call after your existing Sentry initialization.
attachToSentry(Sentry);
const metadata = getUpdateMetadata();

getUpdateMetadata() returns the current update identity (including currentVersion); updateMetadataTags() builds key/value pairs ready for Sentry tags.

Errors and events

  • UpdateError carries a stable machine-readable code (UpdateErrorCode).

  • EventData (the logger callback) includes type (checking, downloading, downloadSuccess, rollback, markSuccess, errorUpdate, …) with error details.

  • For JS error reporting and stack symbolication see Error monitoring.

Pass an initialized reporter with setAttribute/setAttributes to attachToCrashlytics(reporter). The default tag prefix is pakta. and the running update tag is pakta.currentVersion.

Additional optionDefaultPurpose
disableNativeCheckfalseDisable native startup checks
dismissErrorAfterunsetClear lastError after this many milliseconds
overridePackageVersionnative versionDiagnostic JS request override; does not alter the installer

Production defaults to alertUpdateAndIgnoreError; development defaults to alwaysAlert. debug enables checks/downloads in development, not actual activation. updateStrategy also accepts null, but manual Provider calls can still prompt; use the instance methods below for fully custom UI.

checkUpdate(params?)

Call inside an UpdateProvider descendant. With no arguments, checks updates for this device, stores updateInfo and runs the configured prompt/download strategy. extra.toHash selects an update for testing; it does not set the native channel. Returns CheckResult or undefined when skipped. Failures go to lastError by default, or throw with throwError enabled. For a raw result and your own UI, use client.checkUpdate() as shown in the manual example.

typescript
checkUpdate(params?: { extra?: { toHash?: string } }): Promise<CheckResult | undefined>
tsx
const { checkUpdate, lastError } = useUpdate();

async function onCheck() {
  const info = await checkUpdate();
  if (!info) return;
  if (info.expired) {
    return;
  }
  if (info.paused) return;
  if (info.upToDate) return;
  if (info.update) {
  }
}

downloadUpdate(info?)

Uses the latest check result when info is omitted. Returns true after the Provider download flow; false for no usable update or an afterDownloadUpdate veto, even if files already downloaded. It also runs the activation strategy: silentAndNow requests reload, silentAndLater schedules activation, other values can show a prompt. For download only, client.downloadUpdate(info, onProgress?) returns a hash or undefined; client switching methods accept that hash.

typescript
downloadUpdate(info?: CheckResult): Promise<boolean | undefined>
tsx
const { updateInfo, downloadUpdate } = useUpdate();

async function onDownload() {
  if (!updateInfo?.update) return;
  const completed = await downloadUpdate(updateInfo);
  if (!completed) return;
}

downloadAndInstallApk(url)

Downloads a complete Android APK and opens the system installer. The URL must use HTTPS and point to an APK, not an AAB, ppk or store page. Non-Android platforms skip this operation. The APK must match the installed application ID and signing identity and satisfy system version requirements. Promise<void> completion does not prove the user installed the app. Default errors appear in lastError; enable throwError for try/catch.

Add REQUEST_INSTALL_PACKAGES inside manifest, outside application, and rebuild the native installer. The SDK uses Android installation sessions; do not add a FileProvider for this API. Plain HTTP URLs are rejected. The button example below belongs under UpdateProvider and receives the real APK URL, optionally from CheckResult.downloadUrl.

On Android 8+, the user must allow this app to install unknown apps. The SDK opens settings when possible and reports APK_INSTALL_PERMISSION_REQUIRED; after granting permission, return and press the button again. Concurrent downloads are skipped. APK_INSTALL_PENDING means the downloaded APK awaits installation; do not loop downloads. For installation failures check the APK, package ID, signature and version. If distribution requires a store upgrade, use your app’s store link instead.

typescript
downloadAndInstallApk(url: string): Promise<void>
android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
NativeUpgradeButton.tsx
import { useState } from 'react';
import { Button, Platform, Text, View } from 'react-native';
import { useUpdate, useUpdateProgress } from 'rn-update';

export function NativeUpgradeButton({ apkUrl }: { apkUrl: string }) {
  const { downloadAndInstallApk, lastError } = useUpdate();
  const progress = useUpdateProgress();
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState('');

  async function install() {
    if (busy || !apkUrl) return;
    setBusy(true);
    setError('');
    try {
      await downloadAndInstallApk(apkUrl);
    } catch (cause) {
      setError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setBusy(false);
    }
  }

  if (Platform.OS !== 'android') return null;
  const percent = progress?.hash === 'downloadingApk' && progress.total > 0
    ? Math.round(progress.received / progress.total * 100)
    : undefined;
  return (
    <View>
      <Button title={busy ? 'Downloading' : 'Upgrade app'}
        disabled={busy || !apkUrl} onPress={() => { void install(); }} />
      {percent !== undefined ? <Text>{percent}%</Text> : null}
      {error || lastError ? <Text>{error || lastError?.message}</Text> : null}
    </View>
  );
}

markSuccess()

Confirms that the running update is usable. Returns true when native code accepts, false when rejected, or undefined when already marked, in development or outside the first update launch. Native failures throw. The Provider normally confirms after about 1000 ms. For late initialization set autoMarkSuccess:false, then call after critical initialization succeeds. Do not mark success immediately after download. Errors occurring after confirmation do not necessarily trigger rollback.

typescript
markSuccess(): Promise<boolean | undefined>
Existing client options
autoMarkSuccess: false,
After critical initialization
const { markSuccess } = useUpdate();

async function confirmReady() {
  try {
    const accepted = await markSuccess();
    if (accepted === false) {
    }
  } catch (error) {
  }
}

currentVersionInfo

Contains name, description and the JSON-string metaInfo of the running update, or null. updateInfo describes the candidate from the latest check, not the currently running update. currentHash is empty for the embedded bundle; packageVersion is the native installer version and does not change with an update name.

typescript
currentVersionInfo: {
  name?: string;
  description?: string;
  metaInfo?: string;
} | null
tsx
const { currentVersionInfo, currentHash, packageVersion } = useUpdate();
const label = currentVersionInfo?.name || 'Embedded version';

getCurrentVersionInfo()

Compatibility method returning a Promise of name, description and metaInfo. New code should read currentVersionInfo directly.

typescript
getCurrentVersionInfo(): Promise<{
  name?: string;
  description?: string;
  metaInfo?: string;
}>
tsx
const { getCurrentVersionInfo } = useUpdate();
const version = await getCurrentVersionInfo();

restartApp()

Requests a native restart of the React Native environment. It neither checks nor downloads an update and does not promise an OS-level process kill. Save pending work first. beforeReload receives type restartApp; false cancels. Hook and native restart errors reject and should be caught in button handlers.

typescript
restartApp(): Promise<void>
tsx
const { restartApp } = useUpdate();
await restartApp();

resetToPackagedBundle(options?)

Removes downloaded updates and local update state, preserving the device ID. It restores the bundle embedded in the installer, not an arbitrary historical update. By default activation waits for the next launch; restart:true additionally requests restart. A true result proves reset, not successful restart: a hook can veto or restarting can fail. Web returns false; unsupported native builds report RESET_FAILED. Check the result. Stop the faulty server release first or a later check can download it again. See stop release.

typescript
resetToPackagedBundle(options?: { restart?: boolean }): Promise<boolean | undefined>
tsx
const { resetToPackagedBundle } = useUpdate();
const reset = await resetToPackagedBundle({ restart: true });
if (!reset) {
}

switchVersion(info?)

Immediately switches to an already downloaded update. Defaults to the latest CheckResult, skips when no hash exists, and resolves true when native reload is requested, not when the next launch proves healthy. Download first. beforeReload can cancel with false. The client-instance equivalent accepts a string: client.switchVersion(hash).

typescript
switchVersion(info?: CheckResult): Promise<boolean | undefined>
tsx
const { switchVersion, updateInfo } = useUpdate();
if (updateInfo?.hash) await switchVersion(updateInfo);

switchVersionLater(info?)

Schedules an already downloaded update for the next launch, preserving the current screen. Defaults to the latest result; missing hash is skipped. Returns Promise<void> and does not invoke beforeReload. Fully close and reopen to test. The client-instance equivalent is client.switchVersionLater(hash).

typescript
switchVersionLater(info?: CheckResult): Promise<void>
tsx
const { switchVersionLater, updateInfo } = useUpdate();
if (updateInfo?.hash) await switchVersionLater(updateInfo);

parseTestQrCode(code)

Accepts a scanned JSON string or UpdateTestPayload object. A true result only means the test payload was recognized, not that download or activation succeeded. Set type to __rnPaktaVersionHash and data to the full update hash. testChannel:false rejects testing payloads. Supply your own scanner UI. For an existing app deep link, append ?type=__rnPaktaVersionHash&data=HASH; the native scheme must already be configured and rebuilt. This differs from the installer’s fixed distribution channel.

typescript
parseTestQrCode(code: string | UpdateTestPayload): boolean
tsx
const { parseTestQrCode } = useUpdate();
const accepted = parseTestQrCode({
  type: '__rnPaktaVersionHash',
  data: 'REPLACE_WITH_FULL_UPDATE_HASH',
});

useUpdateProgress()

Returns ProgressData or undefined. received and total count bytes; progress is an optional percentage from 0 to 100. APK progress may supply only byte counts. Show an indeterminate state for an unknown total. Use this hook for progress-only components.

tsx
import { Text } from 'react-native';
import { useUpdateProgress } from 'rn-update';

export function DownloadProgress() {
  const data = useUpdateProgress();
  if (!data) return null;
  const percent = data.progress ?? (data.total > 0
    ? Math.round(data.received / data.total * 100) : undefined);
  return <Text>{percent === undefined ? 'Downloading' : `${percent}%`}</Text>;
}

dismissError()

Clears lastError without retrying or modifying downloaded content. Call when dismissing your error UI. dismissErrorAfter:5000 in client options clears it after five seconds.

tsx
const { lastError, dismissError } = useUpdate();

Build a custom update UI

Use instance methods when your UI owns the complete flow. client.downloadUpdate returns a hash, and client switching methods accept a hash; these differ from Hook methods. Add checkStrategy:null and throwError:true to the existing client. Native background checks are separate; disableNativeCheck:true disables them and gives up that recovery path. The example downloads and schedules activation for the next launch, reporting progress and errors.

ManualUpdateButton.tsx
import { useState } from 'react';
import { Button, Text, View } from 'react-native';
import { useUpdate } from 'rn-update';

export function ManualUpdateButton() {
  const { client } = useUpdate();
  const [busy, setBusy] = useState(false);
  const [message, setMessage] = useState('');
  async function update() {
    if (!client || busy) return;
    setBusy(true);
    try {
      const info = await client.checkUpdate();
      if (!info?.update) {
        setMessage(info?.expired ? '请Upgrade app' : 'No available update');
        return;
      }
      const hash = await client.downloadUpdate(info, (data) => {
        setMessage(data.progress === undefined ? 'Downloading' : `${data.progress}%`);
      });
      if (!hash) return;
      await client.switchVersionLater(hash);
      setMessage('Downloaded; applies on next launch');
    } catch (error) {
      setMessage(error instanceof Error ? error.message : String(error));
    } finally {
      setBusy(false);
    }
  }
  return <View>
    <Button title="Check and download" disabled={busy} onPress={() => { void update(); }} />
    <Text>{message}</Text>
  </View>;
}

Check, download and reload hooks

Add hooks to the existing client. beforeCheckUpdate returning false skips checking. afterCheckUpdate receives completed/skipped/error plus result or error and does not replace the result. beforeDownloadUpdate returning false skips download. afterDownloadUpdate returning false stops Provider post-download actions. onPackageExpired returning false prevents built-in installer-upgrade handling. beforeReload receives type switchVersion/restartApp and optional hash; false or a thrown error prevents reload.

The example calls your own savePendingDrafts function, which returns whether it is safe to continue. Bound asynchronous cleanup so the update UI does not wait indefinitely.

tsx
beforeReload: async ({ type }) => {
  if (type === 'switchVersion') {
    const saved = await savePendingDrafts();
    return saved;
  }
  return true;
},

Native startup checks

disableNativeCheck defaults to false: native checks run independently after cold starts and can download repairs when JavaScript is unavailable. checkStrategy:null does not turn off that network request. A server forceBoot directive can schedule repair activation for a later launch; local rollback protection still applies. See brick rescue.

captureException(error, context?)

Use the existing client to report caught JavaScript errors. Uncaught errors are reported automatically. disableErrorReporting disables error reporting specifically; disableTelemetry also blocks the related transport. Include only useful diagnostic context. Archive the matching sourcemap and follow error diagnosis.

tsx
const { client } = useUpdate();
try {
  await submitOrder();
} catch (error) {
  client?.captureException(error, { context: 'checkout' });
}

Android mixed apps: setCustomInstanceManager

For an Android host that owns a ReactInstanceManager instead of a standard ReactApplication, register the same live instance after creating it. This only supplies the reload target. The instance still needs UpdateContext.getBundleUrl(context) as its bundle path. Standard RN apps should follow native integration without creating an additional instance.

java
import cn.reactnative.modules.update.UpdateContext;

UpdateContext.setCustomInstanceManager(reactInstanceManager);