安装与原生接入
按 React Native、Expo 或 HarmonyOS 选择步骤,让 Release 安装包具备加载更新的能力。
更新于 2026-09-15
本页内容
准备好这些
已经能构建的 React Native、Expo 或 RNOH 工程。命令默认在包含
package.json的应用根目录执行。Node.js ≥18.17 和工程原有的平台工具链;iOS 构建需要 macOS。
独立测试应用与设备。先跑通一个平台,再扩展。
SDK 声明 React ≥16.8、React Native ≥0.59,不代表所有版本与架构组合都经过验证。保留项目现有版本,根据现有 MainApplication / AppDelegate 文件选择下面的代码。
安装并取得 appKey
先选择工程类型,复制对应命令,在含 package.json 的目录执行。
npm install -g rn-update-cli
npm install rn-updatenpm install -g rn-update-cli
npx expo install rn-updateiOS 项目继续在 ios 目录执行 pod install(使用 Bundler 时运行 bundle exec pod install),完成后回到应用根目录。Expo 的原生工程在后续构建时生成。
再登录并选择应用:
pakta login
pakta createApp --platform android --name PaktaDemo
pakta selectApp --platform android已有测试应用时跳过 createApp。iOS / HarmonyOS 分别使用 ios / harmony。选择成功后,根目录生成或更新 update.json。
哪个标识填在哪里
| 标识 | 来源 | 使用位置 |
|---|---|---|
appKey | 应用详情或 update.json | SDK 的 new Pakta({ appKey }) |
appId | 应用详情或 update.json | CLI / 管理 API 选择应用 |
PAKTA_API_TOKEN | 控制台 API 令牌入口 | 仅 CLI / CI,不放 App |
接下来只做与你工程对应的一节。
Android:配置 bundle 加载入口
打开 android/app/src/main/java/你的包名/MainApplication.kt。若文件使用 reactHost 与 getDefaultReactHost,在现有宿主中加入 jsBundleFilePath:
import cn.reactnative.modules.update.UpdateContext
// 保留已有的 ReactHost、PackageList 和 getDefaultReactHost 导入。
override val reactHost: ReactHost by lazy {
getDefaultReactHost(
context = applicationContext,
packageList = PackageList(this).packages,
jsBundleFilePath = UpdateContext.getBundleUrl(this),
)
}若使用 DefaultReactNativeHost / ReactNativeHost,同样导入 UpdateContext,在已有 host 对象内覆盖方法,不再创建第二个宿主:
override fun getJSBundleFile(): String? =
UpdateContext.getBundleUrl(this@MainApplication)在现有 android/app/build.gradle 的 release 配置中关闭 PNG 压缩,减少跨构建资源字节差异:
android {
buildTypes {
release {
crunchPngs false
}
}
}依赖由 React Native 自动链接。构建时间由 SDK 自动生成,保留原有签名和构建设置。
先连接根组件,再从 android 目录运行 ./gradlew assembleRelease;Windows 使用 .\gradlew.bat assembleRelease。有 flavor 时使用对应 Release task。
使用 Java 的工程
打开 android/app/src/main/java/你的包名/MainApplication.java,文件顶部添加 import cn.reactnative.modules.update.UpdateContext;,在已有 ReactNativeHost 或 DefaultReactNativeHost 对象内添加:
@Override
protected String getJSBundleFile() {
return UpdateContext.getBundleUrl(MainApplication.this);
}iOS:Release 使用 Pakta bundle
在 ios 目录安装 Pods:使用 Bundler 时执行 bundle exec pod install,否则执行 pod install。
#import "RCTPakta.h"
- (NSURL *)bundleURL
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [RCTPakta bundleURL];
#endif
}保留现有 Debug 入口、模块名与生命周期。Swift 模板让实际 bundle URL 提供者在 Release 返回 RCTPakta.bundleURL(),通过项目 Objective-C bridging header 暴露 RCTPakta.h,不要整份覆盖 AppDelegate。
完成根组件接入,用 Xcode 打开 .xcworkspace,选择签名与设备,以 Release 构建验证。保留同次归档导出的 IPA 用于登记。
Swift 与旧版 AppDelegate
Swift 工程先在 App target 的 Objective-C bridging header 中添加 #import "RCTPakta.h"。如果没有此文件,新建头文件并在 Build Settings 的 Objective-C Bridging Header 填入相对路径,例如 YourApp/YourApp-Bridging-Header.h。
找到现有提供 bundle URL 的方法,替换 Release 分支。新模板可能把方法放在 ReactNativeDelegate 中,应在那里修改:
override func bundleURL() -> URL? {
#if DEBUG
return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
return RCTPakta.bundleURL()
#endif
}旧 Objective-C 模板若只有 sourceURLForBridge:,保留方法签名,把其中非 DEBUG 分支改为 return [RCTPakta bundleURL];。混编工程使用 bridge delegate 提供 URL,避免直接用固定文件路径创建 root view。
Expo:构建包含原生模块的 App
Expo Go 不包含 rn-update 原生模块。按顺序操作:
安装依赖:执行
npx expo install rn-update。需要自定义渠道时,在expo.plugins加入内置 Config Plugin。连接根布局:在
app/_layout.tsx用UpdateProvider包裹已有Stack/Slot,客户端在组件外创建。构建原生 App:运行
npx expo run:android --variant release,iOS 使用npx expo run:ios --configuration Release,或项目已有 EAS production profile。安装并验证:确认脱离 Metro 可启动;后续生成 OTA 使用
bundle --expo,平台仍为android/ios。
完整步骤见Expo 接入。
HarmonyOS:按 RNOH 示例接线
HarmonyOS 需要 HAR、ArkTS 与 C++ 注册,不能只安装 npm 包。逐项对照示例:
以下路径假设 node_modules 与 harmony 都在应用根目录。将配置合并到已有文件,保留现有插件和包列表;不要替换整个工程文件。
给 entry 添加 Pakta HAR 依赖。
给 entry 的 Hvigor 构建添加
reactNativeUpdatePlugin()。在 ArkTS 和 C++ 两处现有包列表中加入 Pakta。
在 Release 的
RNApp中优先加载 Pakta 更新,找不到更新时加载内置bundle.harmony.js。
"pakta": "file:../../node_modules/rn-update/harmony/pakta.har"import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { reactNativeUpdatePlugin } from '../../node_modules/rn-update/harmony/hvigor-plugin';
export default {
system: hapTasks,
plugins: [reactNativeUpdatePlugin()],
};import type { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony';
import PaktaPackage from 'pakta';
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
return [new PaktaPackage(ctx)];
}set(PAKTA_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules/rn-update/harmony/pakta/src/main/cpp")
target_include_directories(rnoh_app PRIVATE "${PAKTA_CPP_DIR}")
target_sources(rnoh_app PRIVATE "${PAKTA_CPP_DIR}/PaktaTurboModule.cpp")#include "RNOH/PackageProvider.h"
#include "PaktaPackage.h"
using namespace rnoh;
std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
return {std::make_shared<PaktaPackage>(ctx)};
}import { PaktaFileJSBundleProvider } from 'pakta';
import { AnyJSBundleProvider, ResourceJSBundleProvider } from '@rnoh/react-native-openharmony';jsBundleProvider: new AnyJSBundleProvider([
new PaktaFileJSBundleProvider(this.rnohCoreContext.uiAbilityContext),
new ResourceJSBundleProvider(
this.rnohCoreContext.uiAbilityContext.resourceManager,
'bundle.harmony.js'
),
]),运行前确认 this.rnohCoreContext 已就绪。保留工程原有 RNApp 其他参数;Release 不要把 Metro 放在更新文件前面。
pakta bundle --platform harmony --output .pakta/output/harmony.ppk --no-interactive在 DevEco Studio 同步、签名并构建原生 .app。确认生成的 rawfile bundle 与宿主资源路径一致,安装验证后用 uploadApp 登记。
完整工程在 SDK 示例目录:testHotUpdate、expoUsePakta、harmony_use_pakta。示例的仓库相对路径需要改为你的依赖路径。
自托管:分别配置 SDK 和 CLI
托管服务用户跳过。SDK 连接公开更新接口,CLI 连接管理接口:
server: {
main: ['https://YOUR_HOST/api'],
queryUrls: ['https://YOUR_CDN/endpoints.json'],
},替换为真实部署地址;端点清单必须属于你的部署。登录 CLI 前设置主机:
$env:RNU_SERVICE_URL = 'https://YOUR_HOST'export RNU_SERVICE_URL=https://YOUR_HOST手动链接:只处理未自动接入的工程
React Native 0.60 及以上通常自动链接,先运行 npx react-native config 检查 rn-update 是否被发现,iOS 再安装 Pods。已自动链接时跳过本节,重复注册会出错。
旧工程 Android 在 android/settings.gradle 引入 node_modules/rn-update/android,在 app 的 dependencies 中添加 implementation project(':rn-update'),再把 new UpdatePackage() 加入已有 getPackages 列表(导入 cn.reactnative.modules.update.UpdatePackage)。三处必须一起配置。
include ':rn-update'
project(':rn-update').projectDir = new File(rootProject.projectDir, '../node_modules/rn-update/android')implementation project(':rn-update')iOS 未自动发现依赖时,在已有 Podfile 的 App target 中添加 pod 'rn-update', :path => '../node_modules/rn-update',再运行 pod install。完成链接后仍需配置前面的 bundle 加载入口。
Android 页面恢复:使用 react-native-screens 时
使用 react-native-screens 的工程检查 MainActivity 的恢复配置,避免重载后恢复旧页面状态导致崩溃。下面适用于依赖已提供 RNScreensFragmentFactory 的版本,放在现有 MainActivity 类中,不能放进 MainActivityDelegate:
import android.os.Bundle
import com.swmansion.rnscreens.fragment.restoration.RNScreensFragmentFactory
override fun onCreate(savedInstanceState: Bundle?) {
supportFragmentManager.fragmentFactory = RNScreensFragmentFactory()
super.onCreate(savedInstanceState)
}已有 onCreate 时合并到原方法,不添加第二个;旧版本没有该类时,按所用 screens 版本的安装说明处理,不直接导入不存在的类。
可选:用链接打开测试更新
已有扫码页面时直接调用parseTestQrCode。想从浏览器或相机打开 App 时,再配置一个你自己使用的 scheme,例如 paktademo。
Android 在已有 MainActivity 的 <activity> 内增加独立 intent-filter,保留原有启动 filter,并确认 activity 使用 android:launchMode="singleTask":
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="paktademo" />
</intent-filter>iOS 在 App target 的 Info → URL Types 新增 URL Scheme paktademo,并保留工程现有 React Native Linking 的 AppDelegate 转发。Expo 在 expo.scheme 中设置同一名称。修改后重新构建安装包。
上传测试更新后,从控制台复制完整 hash,打开 paktademo://update?type=__rnPaktaVersionHash&data=实际HASH。Provider 识别后检查该更新;继续按 App 策略下载、生效。testChannel: false 会拒绝测试载荷。
Android AAB 安装包
Google Play 使用 AAB 时,保留实际提交的 AAB,执行 pakta parseAab 路径 检查,再用 pakta uploadAab 路径 登记。不要用另一次构建的 APK 代替。
不要为了接入盲目关闭所有语言、密度、ABI 分割。先按实际分发包验证资源和更新;某个 split 缺失资源时,检查资源打包配置及对应原生版本。
下一步
依赖已安装、CLI 已选中正确平台应用、原生入口已配置。前往让 App 检查更新,加上 Provider 与版本面板,再构建安装包。
Expo 本地构建参数参照 Expo CLI 官方文档。
