文档

SDK API 参考

查阅公开入口、配置默认值、Hooks、检查结果与错误模型。

更新于 2026-09-14

本页内容

先完成最小接入。本页用于查找参数,不要求一次配置所有选项。示例默认已有一个客户端实例;不要为错误上报或动态配置再创建第二个实例。

概览

Pakta SDK(npm 包 rn-update)的公开 API 全部从包入口导出。核心分五块:

  • Pakta 客户端类与 ClientOptions 配置

  • UpdateProvider(别名 PaktaProvider)React 接入层

  • useUpdate() / useUpdateProgress() / usePakta() Hooks

  • 更新元数据与崩溃报告关联

  • UpdateError 错误类型与事件模型

客户端类

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

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

// 运行中动态更新配置(合并新配置,并通知 Provider)
client.setOptions({ checkStrategy: 'onAppResume' });

// 手动上报 JS 异常(默认自动监听未捕获的 JS 错误)
client.captureException(error, { context: 'checkout' });

ClientOptions

字段类型默认说明
appKeystring必填控制台分配的平台 appKey
server{ main: string[]; queryUrls?: string[] }官方默认端点自托管服务地址与端点发现清单
updateStrategy见下表生产为 'alertUpdateAndIgnoreError',开发为 'alwaysAlert'更新提示与生效策略
checkStrategy'onAppStart' | 'onAppResume' | 'both' | null'both'检查时机;null 关闭 JS 自动检查
autoMarkSuccessbooleantrue自动确认当前版本健康
autoMarkSuccessDelayMsnumber1000自动确认延迟;关键模块加载晚时调大
healthCheck() => boolean | Promise<boolean>确认前的健康检查;返回 false 跳过本次确认
maxRetriesnumber3下载失败重试次数
logger({ type, data }) => void更新事件记录器
locale'zh' | 'en''zh'内置提示文案语言
debugbooleanfalse允许在开发构建检查和下载;实际生效仍用 Release
throwErrorbooleanfalse把更新错误抛给 JS 层
testChannelbooleantrue是否响应测试二维码/深链;生产建议 false
beforeCheckUpdate / afterCheckUpdate钩子检查前后拦截与回调
beforeDownloadUpdate / afterDownloadUpdate钩子下载前后拦截与回调
beforeReload(ctx: { type: 'switchVersion' | 'restartApp' }) => …重载前拦截
onPackageExpired钩子原生包过期时拦截默认行为
disableTelemetrybooleanfalse关闭客户端遥测及 JS 错误传输
disableErrorReportingbooleanfalse单独关闭 JS 错误上报
disableNativeCheckbooleanfalse关闭原生冷启动检查,见下方说明
dismissErrorAfternumber不自动清除自动清除 lastError 的延迟,毫秒
overridePackageVersionstring原生实际版本诊断时覆盖 JS 请求版本,不会修改安装包;正常发布不设置

updateStrategy 取值:'silentAndNow''silentAndLater''alertUpdateAndIgnoreError''alwaysAlert'null。当前 Provider 在手动检查/下载后仍可能弹窗;完全自定义流程使用下方实例 API 示例。

React 接入

tsx
import { Pakta, UpdateProvider, PaktaProvider, useUpdate, usePakta, useUpdateProgress } from 'rn-update';
  • UpdateProvider / PaktaProvider(别名)——接收 client prop;同一进程重复挂载第二个 Provider 会直接抛错。

  • useUpdate() —— 读取更新状态与动作(见下)。

  • useUpdateProgress() —— 单独订阅下载进度 { hash, received, total, progress? }

  • usePakta() —— useUpdate() 的别名,返回相同状态与动作;实例通过 useUpdate().client 取得。

useUpdate() 返回的 UpdateContextValue

成员说明
updateInfo最近一次 CheckResult
lastError最近一次错误
currentHash / packageVersion当前热更新 hash 与原生包版本
currentVersionInfo{ name?, description?, metaInfo? }
checkUpdate(params?)手动检查
downloadUpdate(info?)下载
switchVersion(info?)立即切换已下载版本(重载 JS)
switchVersionLater(info?)下次启动生效
markSuccess()确认当前版本健康
restartApp()重启应用
resetToPackagedBundle(options?)回到内置 bundle
downloadAndInstallApk(url)下载并安装原生升级包(原生包过期场景)
parseTestQrCode(code)解析测试二维码/深链
dismissError()清除 lastError

CheckResult 与版本信息

ts
interface CheckResult {
  upToDate?: boolean;      // 已是最新
  update?: boolean;        // 有可用更新
  expired?: boolean;       // 原生包过期,downloadUrl 指向新安装包
  paused?: 'app' | 'package'; // 应用或原生包暂停
  downloadUrl?: string;    // 过期安装包地址
  bundleStatus?: 'matched' | 'rebuiltSameJs' | 'unknownBundle';
  name?: string;           // 版本名
  hash?: string;           // 版本 hash
  description?: string;    // 版本描述
  metaInfo?: string;       // 自定义元信息(JSON 字符串)
  config?: { rollout?: Record<string, number>; forceBoot?: boolean };
  pdiff?: string;          // 精确差分包地址
  diff?: string;           // 普通差分包地址
  full?: string;           // 全量包地址
}

bundleStatus 说明原生包登记状态:matched 完全匹配;rebuiltSameJs 同 JS 指纹但构建时间不同(只允许全量);unknownBundle 指纹未登记(严格渠道下保持当前版本)。

元数据与崩溃报告关联

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

// 在已有 Sentry 初始化之后调用。
attachToSentry(Sentry);
const metadata = getUpdateMetadata();

getUpdateMetadata() 返回当前更新版本信息(含 currentVersion),updateMetadataTags() 生成可直接挂到 Sentry tags 的键值对。

错误与事件

  • UpdateError 携带稳定的机器可读 codeUpdateErrorCode)。

  • EventDatalogger 回调)包含 type(如 checkingdownloadingdownloadSuccessrollbackmarkSuccesserrorUpdate…)与错误详情。

  • JS 错误上报与堆栈还原见 JS 报错监控

Crashlytics 需向 attachToCrashlytics(reporter) 传入已初始化且提供 setAttribute/setAttributes 的实例。默认标签前缀为 pakta.,当前更新标签为 pakta.currentVersion

checkUpdate(params?)

UpdateProvider 的子组件中调用。检查后会更新 updateInfo,并执行所选更新策略,可能继续下载或弹窗。

typescript
checkUpdate(params?: { extra?: { toHash?: string } }): Promise<CheckResult | undefined>

不传参数检查当前设备可用的更新。extra.toHash 用于测试指定更新,不用于设置渠道。跳过检查时可能返回 undefined;失败默认记录到 lastError,配置 throwError: true 后可以捕获异常。

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

async function onCheck() {
  const info = await checkUpdate();
  if (!info) return;
  if (info.expired) {
    // 当前安装包需要升级,下载地址在 info.downloadUrl。
    return;
  }
  if (info.paused) return;
  if (info.upToDate) return;
  if (info.update) {
    // 后续下载和生效行为取决于 updateStrategy。
  }
}

只想取得原始检查结果、自行画界面时使用 client.checkUpdate(),不要同时调用 Provider 和 client 两套检查流程。完整手动示例见自定义更新界面

downloadUpdate(info?)

typescript
downloadUpdate(info?: CheckResult): Promise<boolean | undefined>

info 默认是最近一次检查结果。没有可下载更新时返回 false;成功完成 Provider 下载流程时返回 trueafterDownloadUpdate 返回 false 时也返回 false,即使文件已经下载。

tsx
const { updateInfo, downloadUpdate } = useUpdate();

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

Provider 的这个方法会继续执行下载后的策略:silentAndNow 请求立即重载,silentAndLater 安排下次启动,其余情况可能显示生效提示。不要把它当成“只下载文件”的接口。

只下载时调用 client.downloadUpdate(info, onProgress?):返回 Promise<string | undefined>,字符串是下载完成的更新 hash;然后自己调用 client.switchVersion(hash)client.switchVersionLater(hash)

downloadAndInstallApk(url)

下载完整 Android 安装包并打开系统安装界面,用于需要升级原生版本的情况。它不安装 .ppk,也不负责 iOS 或 HarmonyOS 安装。

typescript
downloadAndInstallApk(url: string): Promise<void>
项目要求
url可直接下载的 HTTPS APK 地址,不是商店网页或 AAB
平台Android;其他平台跳过
安装包与当前 App 包名和签名匹配,版本符合系统升级要求
返回值无;Promise 完成不代表用户已确认安装
错误默认在 lastError 中;throwError: true 时可用 try/catch

1. 添加安装权限

在 App 的 android/app/src/main/AndroidManifest.xml 中,放到 <manifest> 内、<application> 外:

android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

重新构建并分发安装包,权限不会通过 JS 更新加入。SDK 使用 Android 系统安装会话,不需要额外添加 FileProvider。HTTP 地址会被拒绝。

2. 添加升级按钮

下面组件放在现有 UpdateProvider 下。apkUrl 由业务传入实际 APK 下载地址,也可以来自检查结果的 downloadUrl

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 ? '正在下载' : '升级安装包'}
        disabled={busy || !apkUrl} onPress={() => { void install(); }} />
      {percent !== undefined ? <Text>{percent}%</Text> : null}
      {error || lastError ? <Text>{error || lastError?.message}</Text> : null}
    </View>
  );
}

3. 处理系统授权和安装结果

Android 8 及以上需要允许当前 App 安装未知来源应用。权限未开启时,SDK 尝试打开系统设置,并报告 APK_INSTALL_PERMISSION_REQUIRED。用户允许后回到 App,再点升级按钮。

下载过程中重复调用会跳过。已经下载并等待安装时,再调用可能得到 APK_INSTALL_PENDING;让用户完成系统安装,不要循环下载。权限已允许但安装失败时,检查 APK 是否完整、包名、签名和版本号。

如果发布渠道要求通过商店更新,使用业务自己的商店跳转,不调用 APK 安装方法。

markSuccess()

确认当前更新已经能正常使用,结束此次新版本启动的回滚保护。

typescript
markSuccess(): Promise<boolean | undefined>

返回 true 表示原生层接受确认;false 表示拒绝;已确认、开发环境或不在新版本首次启动时可能返回 undefined。原生调用失败会抛错。

默认 Provider 在挂载后约 1000 ms 自动确认。只有需要等关键页面或初始化完成时才关闭自动确认:

加入现有 client 配置
autoMarkSuccess: false,
关键初始化成功后
const { markSuccess } = useUpdate();

async function confirmReady() {
  try {
    const accepted = await markSuccess();
    if (accepted === false) {
      // 未接受确认,保留诊断信息。
    }
  } catch (error) {
    // 展示或记录确认失败,不要当成已成功。
  }
}

不要在刚下载完时确认:要确认的是新版本启动成功。已确认后的任意业务异常不一定触发自动回滚。

currentVersionInfo

typescript
currentVersionInfo: {
  name?: string;
  description?: string;
  metaInfo?: string;
} | null

表示当前运行更新的名称、说明和自定义数据。updateInfo 则是最近检查到的候选更新,两者不要混用。

tsx
const { currentVersionInfo, currentHash, packageVersion } = useUpdate();
const label = currentVersionInfo?.name || '安装包自带版本';

currentHash 为空表示正在使用安装包自带的 JS。packageVersion 是原生安装包版本,不会因为热更新名称变化而改变。

getCurrentVersionInfo()

typescript
getCurrentVersionInfo(): Promise<{
  name?: string;
  description?: string;
  metaInfo?: string;
}>

兼容旧代码的异步方法,新代码直接读取 currentVersionInfo

tsx
const { getCurrentVersionInfo } = useUpdate();
const version = await getCurrentVersionInfo();

restartApp()

typescript
restartApp(): Promise<void>

请求原生层重启 React Native 应用环境。它不会检查或下载更新,也不保证操作系统杀掉整个 App 进程。调用前保存草稿、支付状态等必要数据。

tsx
const { restartApp } = useUpdate();
await restartApp();

调用前执行 beforeReload({ type: 'restartApp' }),返回 false 取消重启。钩子或原生重启失败会抛错,应在按钮回调中捕获。

resetToPackagedBundle(options?)

清除已下载更新和本地更新状态,恢复安装包自带的 JS,保留设备标识。它不是选择某个历史热更新。

typescript
resetToPackagedBundle(options?: { restart?: boolean }): Promise<boolean | undefined>
tsx
const { resetToPackagedBundle } = useUpdate();
const reset = await resetToPackagedBundle({ restart: true });
if (!reset) {
  // 重置没有成功,不要向用户显示“已恢复”。
}

默认不立即重启,下次启动加载内置包;restart: true 会在重置后请求重启。返回 true 只表示重置成功,重启可能被钩子取消或失败。Web 返回 false;不支持此原生方法的旧安装包会报告 RESET_FAILED。服务端仍发布相同更新时,后续检查可能再次下载,运营应先停止问题版本

switchVersion(info?)

typescript
switchVersion(info?: CheckResult): Promise<boolean | undefined>

立即切换到已经下载的更新,参数默认最近检查结果。无 hash 时跳过;返回 true 表示已请求原生重载,不能当成新版本已正常启动。

tsx
const { switchVersion, updateInfo } = useUpdate();
if (updateInfo?.hash) await switchVersion(updateInfo);

必须先下载。该方法执行 beforeReload,返回 false 可取消;当前页面会在重载时中断。调用客户端实例对应的方法时传 hash 字符串:client.switchVersion(hash)

switchVersionLater(info?)

typescript
switchVersionLater(info?: CheckResult): Promise<void>

把已下载更新设为下次启动使用的版本,保持当前页面。无 hash 时跳过,不触发 beforeReload

tsx
const { switchVersionLater, updateInfo } = useUpdate();
if (updateInfo?.hash) await switchVersionLater(updateInfo);

测试时完整关闭并重新启动 App,仅切换页面不算重启。客户端实例用法为 client.switchVersionLater(hash)

parseTestQrCode(code)

typescript
parseTestQrCode(code: string | UpdateTestPayload): boolean

接受扫码得到的 JSON 字符串或对象。返回 true 只表示识别了测试载荷,不代表下载或生效成功。

tsx
const { parseTestQrCode } = useUpdate();
const accepted = parseTestQrCode({
  type: '__rnPaktaVersionHash',
  data: '替换成控制台里目标更新的完整 hash',
});

识别后会检查指定更新;仍需观察后续检查结果。testChannel: false 拒绝测试载荷。扫码组件由业务提供,SDK 不会替你打开摄像头。

使用已有 App 深链时,可传 ?type=__rnPaktaVersionHash&data=HASH,Provider 会读取查询参数。原生 scheme 仍需在工程中配置并重新构建。扫码测试与安装包里的固定渠道是两个设置。

useUpdateProgress()

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 ? '正在下载' : `${percent}%`}</Text>;
}

返回 ProgressData | undefinedreceived / total 为字节数,progress 是可选的 0–100 百分比。APK 进度可能只有字节数;未知总量时显示下载中。仅需进度的组件用此 Hook,可减少其他更新状态变化带来的渲染。

dismissError()

清空 Provider 的 lastError,不会重试或改变已下载的内容。

tsx
const { lastError, dismissError } = useUpdate();
// 在用户关闭错误提示时调用 dismissError()。

需要自动清除时,把 dismissErrorAfter: 5000 加入现有客户端配置,单位毫秒。

自定义更新界面

实例的 checkUpdate / downloadUpdate 用于自己控制流程。它们和 Hook 方法的参数、返回值不同:实例下载返回 hash,实例切换接受 hash。

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 ? '请升级安装包' : '暂无可下载更新');
        return;
      }
      const hash = await client.downloadUpdate(info, (data) => {
        setMessage(data.progress === undefined ? '正在下载' : `${data.progress}%`);
      });
      if (!hash) return;
      await client.switchVersionLater(hash);
      setMessage('下载完成,下次启动生效');
    } catch (error) {
      setMessage(error instanceof Error ? error.message : String(error));
    } finally {
      setBusy(false);
    }
  }
  return <View>
    <Button title="检查并下载" disabled={busy} onPress={() => { void update(); }} />
    <Text>{message}</Text>
  </View>;
}

配套把 checkStrategy: nullthrowError: true 加入现有客户端。checkStrategy 只关闭 JS 自动检查;需要同时关闭原生后台检查时另设 disableNativeCheck: true,并接受失去原生救援能力的影响。

检查、下载和重载钩子

配置收到什么返回值如何影响流程
beforeCheckUpdate无参数false 跳过本次检查
afterCheckUpdate{ status, result?, error? }记录检查完成、跳过或失败,不替换结果
beforeDownloadUpdateCheckResultfalse 跳过下载
afterDownloadUpdateCheckResultfalse 停止 Provider 下载后的提示或切换
onPackageExpiredCheckResultfalse 阻止内置原生升级处理
beforeReload{ type, hash? }false 取消立即重载;抛错也不继续

这些配置都加入根组件外的已有客户端。比如在立即重载前等待业务保存:

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

savePendingDrafts 是业务自己的保存函数,应返回是否可以继续。等待操作设置合理超时,避免更新按钮永久等待。

原生启动检查

disableNativeCheck 默认关闭,即原生检查启用。它在 App 冷启动后独立检查更新,JS 不能运行时也能下载修复。

checkStrategy: null 不会关闭这次网络请求;服务端 forceBoot 可以安排修复在后续启动生效。本地已回滚版本仍受保护。操作入口见强制救砖

captureException(error, context?)

使用已有客户端记录业务捕获的 JS 异常,无需再创建一个实例:

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

未捕获 JS 错误默认自动上报;disableErrorReporting 单独关闭错误上报,disableTelemetry 也会阻止相关传输。上下文只放诊断所需信息。对应 sourcemap 的归档和还原见报错监控

Android 混编:setCustomInstanceManager

已有原生 Android 工程自己维护 ReactInstanceManager、没有标准 ReactApplication 时,把同一个正在使用的实例交给 SDK,供重载使用:

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

UpdateContext.setCustomInstanceManager(reactInstanceManager);

在创建该实例后调用。它不代替 bundle 路径配置,构建实例时仍需使用 UpdateContext.getBundleUrl(context);标准 React Native 工程按原生接入即可,无需额外创建实例。