Skip to main content

Shiply ReactNative 动态化 SDK 接入指引

一、隐私安全说明

Shiply ReactNative 动态化 SDK

二、SDK 接入

可以参考 ShiplyReactNativeUpgradeDemo 项目进行接入。

2.1 引入 Shiply RN 动态化扩展包

2.1.1 添加 RN 层依赖

在项目根目录执行:

npm install rn-shiply-upgrade

2.1.2 添加 Android 层依赖

在项目 Android 目录下的 build.gradle 文件中添加 maven 地址:

allprojects {
repositories {
maven { url "https://maven.cnb.cool/tencent-tds/shiply-public/-/packages/" }
}
}

2.1.3 添加 iOS 层依赖

暂时不需要额外设置。

2.1.4 添加 HarmonyOS 层依赖

步骤 1:配置模块路径

HarmonyOS 工程根目录build-profile.json5 中添加模块配置:

{
"modules": [
// ... 其他模块
{
"name": "ohrn_shiply_upgrade",
"srcPath": "../node_modules/rn-shiply-upgrade/harmony/shiply_react_native_upgrade"
},
{
"name": "entry",
"srcPath": "./entry"
}
]
}
tip

srcPath 需要根据你的项目目录结构调整,确保路径指向 rn-shiply-upgrade/harmony/shiply_react_native_upgrade 目录。

步骤 2:配置 entry 依赖

entry/oh-package.json5 中添加依赖:

{
"dependencies": {
"@rnoh/react-native-openharmony": "^0.72.96",
"ohrn_shiply_upgrade": "file:../../node_modules/rn-shiply-upgrade/harmony/shiply_react_native_upgrade"
}
}
步骤 3:配置 MMKV 版本

由于 Shiply SDK 依赖 @tencent/mmkv,为避免版本冲突,需要在 HarmonyOS 工程根目录oh-package.json5 中添加版本覆盖:

{
"overrides": {
"@tencent/mmkv": "2.2.4"
}
}
danger

此步骤非常重要,版本不一致可能导致运行时错误。

步骤 4:配置 C++ 构建

entry/src/main/cpp/CMakeLists.txt 中添加:

# ... 其他配置

# 添加 shiply upgrade 模块
add_subdirectory("${OH_MODULE_DIR}/ohrn_shiply_upgrade/src/main/cpp" ./shiply_upgrade)
target_link_libraries(rnoh_app PUBLIC rnoh_shiply_upgrade)

target_link_libraries(rnoh_app PUBLIC rnoh)
步骤 5:注册 C++ Package

entry/src/main/cpp/PackageProvider.cpp 中添加:

#include "RNOH/PackageProvider.h"
#include "ShiplyReactNativeUpgradePackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
return {
// ... 其他 Package
std::make_shared<ShiplyReactNativeUpgradePackage>(ctx)
};
}
步骤 6:注册 TypeScript Package

entry/src/main/ets/RNPackagesFactory.ets 中添加:

import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';
import { ShiplyReactNativeUpgradePackage } from "ohrn_shiply_upgrade";

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
return [
// ... 其他 Package
new ShiplyReactNativeUpgradePackage(ctx)
];
}

2.2 添加热更新检查与加载代码

2.2.1 修改 RN 层代码

import { Text, View, Image, Platform } from 'react-native';
import DeviceInfo from 'react-native-device-info';
import { HotUpdateHelper, HotUpdateButton } from 'rn-shiply-upgrade'; // 新增导入辅助类

const AppV2 = () => {
// 初始化热更新配置(只需一次)
HotUpdateHelper.getInstance({
// 需要修改为业务方自己的 android/ios appId 和 appKey
appId: Platform.OS === 'ios' ? 'xxx1' : 'xxx2',
appKey: Platform.OS === 'ios'
? 'xxxxx1'
: 'xxxxx2',
deviceId: '33333', // 需要修改为实际的设备 id
appVersion: DeviceInfo.getVersion(), // 应用版本号
isDebugPackage: false,
customParamsByJson: JSON.stringify({ age: '22', name: 'testName' }), // 自定义请求参数,按需设置
env: 'online', // 环境类型
shiplyResName: 'testRN', // 资源 key 名称,对应 Shiply 平台上创建的资源 key
eventLogger: ({ type, data }) => {
console.log(`[HotUpdate] ${type}:`, data);
}
});

return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
{/* 默认样式按钮 */}
<HotUpdateButton />
</View>
);
};

export default AppV2;
tip
  • 点击按钮即可触发更新检测请求
  • 也可以参考 HotUpdateButton 中相关代码自定义请求时机和 UI 表现

2.2.2 修改 Android 层代码

class MainApplication : Application(), ReactApplication {

override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
}

override fun getJSMainModuleName(): String = "index"

override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

override fun getJSBundleFile(): String? {
var result: String? = null
// 从 Shiply 获取 RN bundle 路径,业务方需要将资源 key 修改为 Shiply 平台中创建的资源 key 名称
result = ShiplyReactNativeUpgradeModule.getJSBundleFilePath(applicationContext as Application, "testRN")
Log.d(TAG, "getJSBundleFile: $result")
return result
}

override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}
}

复写 getJSBundleFile 方法,从 Shiply 获取 bundle 路径,业务方需要将资源 key 修改为 Shiply 平台中创建的资源 key 名称。

日志配置

Shiply ReactNative 动态化 SDK native 层日志打印是对接的 RN 框架的日志接口,可以参考以下代码将 RN 日志对接到业务方自己的日志系统。

Android 日志配置示例代码:

FLog.setLoggingDelegate(object : LoggingDelegate {
private var logLevel = FLog.INFO // 默认日志级别
private val prefix = "TestFlog_"
override fun setMinimumLoggingLevel(level: Int) {
logLevel = level
}

override fun getMinimumLoggingLevel(): Int = logLevel

override fun isLoggable(level: Int): Boolean = level >= logLevel


override fun v(tag: String, msg: String) {
log(FLog.VERBOSE, tag, msg)
}

override fun v(tag: String, msg: String, tr: Throwable) {
log(FLog.VERBOSE, tag, "$msg\n${Log.getStackTraceString(tr)}")
}

override fun d(tag: String, msg: String) {
log(FLog.DEBUG, tag, msg)
}

override fun d(tag: String, msg: String, tr: Throwable) {
log(FLog.DEBUG, tag, "$msg\n${Log.getStackTraceString(tr)}")
}

override fun i(tag: String, msg: String) {
log(FLog.INFO, tag, msg)
}

override fun i(tag: String, msg: String, tr: Throwable) {
log(FLog.INFO, tag, "$msg\n${Log.getStackTraceString(tr)}")
}

override fun w(tag: String, msg: String) {
log(FLog.WARN, tag, msg)
}

override fun w(tag: String, msg: String, tr: Throwable) {
log(FLog.WARN, tag, "$msg\n${Log.getStackTraceString(tr)}")
}

override fun e(tag: String, msg: String) {
log(FLog.ERROR, tag, msg)
}

override fun e(tag: String, msg: String, tr: Throwable) {
log(FLog.ERROR, tag, "$msg\n${Log.getStackTraceString(tr)}")
}

override fun wtf(tag: String, msg: String) {
Log.wtf(tag, msg)
}

override fun wtf(tag: String, msg: String, tr: Throwable) {
Log.wtf(tag, msg, tr)
}

override fun log(priority: Int, tag: String, msg: String) {
val newTag = prefix + tag
when (priority) {
FLog.VERBOSE -> Log.v(newTag, msg)
FLog.DEBUG -> Log.d(newTag, msg)
FLog.INFO -> Log.i(newTag, msg)
FLog.WARN -> Log.w(newTag, msg)
FLog.ERROR -> Log.e(newTag, msg)
else -> Log.println(priority, newTag, msg)
}
}
})

2.2.3 修改 iOS 层代码

import UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
import ShiplyReactNativeUpgrade

@main
class AppDelegate: RCTAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
self.moduleName = "ShiplyReactNativeUpgradeExample"
self.dependencyProvider = RCTAppDependencyProvider()
self.initialProps = [:]
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

override func sourceURL(for bridge: RCTBridge) -> URL? {
self.bundleURL()
}

override func bundleURL() -> URL? {
#if DEBUG
let buildConfig = "Debug"
#else
let buildConfig = "Release"
#endif

NSLog("bundleURL called - Build Configuration: \(buildConfig)")

// 业务方需要将资源 key 修改为 Shiply 平台中创建的资源 key 名称
ShiplyReactNativeUpgradeUtil.getJSBundleFilePath("testRN");
if let path = ShiplyReactNativeUpgradeUtil.getJSBundleFilePath("testRN") {
NSLog("bundleURL called,path = %@ ", path);

return URL(fileURLWithPath: path)
}
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
}
}

复写 bundleURL 方法,从 Shiply 获取 bundle 路径,业务方需要将资源 key 修改为 Shiply 平台中创建的资源 key 名称。

日志配置

Shiply ReactNative 动态化 SDK native 层日志打印是对接的 RN 框架的日志接口,可以参考以下代码将 RN 日志对接到业务方自己的日志系统。

iOS 日志配置示例代码:

RCTSetLogThreshold(RCTLogLevelInfo);
RCTLogFunction customLogFunction = ^(RCTLogLevel level,
RCTLogSource source,
NSString *fileName,
NSNumber *lineNumber,
NSString *message)
{
NSString *levelStr;
switch (level) {
case RCTLogLevelError: levelStr = @"🔴 ERROR"; break;
case RCTLogLevelWarning: levelStr = @"⚠️ WARN"; break;
default: levelStr = @"INFO"; break;
}

NSString *sourceStr = (source == RCTLogSourceNative) ? @"[Native]" : @"[JS]";

NSLog(@"TestAPP_%@ %@ %@:%@ %@",
levelStr,
sourceStr,
fileName,
lineNumber,
message);
};
// 设置自定义日志函数
RCTSetLogFunction(customLogFunction);

2.2.4 修改 HarmonyOS 层代码

entry/src/main/ets/pages/Index.ets 中配置热更新 Bundle 加载器:

import {
AnyJSBundleProvider,
MetroJSBundleProvider,
ResourceJSBundleProvider,
RNApp,
TraceJSBundleProviderDecorator,
RNOHCoreContext
} from '@rnoh/react-native-openharmony';
import { createRNPackages } from '../RNPackagesFactory';
import { ShiplyFileJSBundleProvider } from 'ohrn_shiply_upgrade';

@Entry
@Component
struct Index {
@StorageLink('RNOHCoreContext') private rnohCoreContext: RNOHCoreContext | undefined = undefined

// ... 其他代码

build() {
Column() {
if (this.rnohCoreContext) {
RNApp({
rnInstanceConfig: {
createRNPackages,
enableNDKTextMeasuring: true,
enableBackgroundExecutor: false,
enableCAPIArchitecture: true,
arkTsComponentNames: []
},
initialProps: {} as Record<string, string>,
appKey: "YourAppName", // 替换为你的 RN 应用名称
jsBundleProvider: new TraceJSBundleProviderDecorator(
new AnyJSBundleProvider([
// 热更新 Bundle Provider(放在最前面,优先加载)
// 'resId' 参数是你在 Shiply 平台配置的资源 ID
new ShiplyFileJSBundleProvider(this.rnohCoreContext.uiAbilityContext, 'your_res_id'),

// 开发调试用 Metro Provider
new MetroJSBundleProvider(),

// 内置 Bundle(兜底)
new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js')
]),
this.rnohCoreContext.logger
),
})
}
}
.height('100%')
.width('100%')
}
}
重要说明
  • ShiplyFileJSBundleProvider 必须放在 Provider 列表的 最前面,这样会优先尝试加载热更新包
  • 第二个参数 resId 是你在 Shiply 平台配置的资源 ID,用于区分不同的热更新资源

三、打包 RN 动态化产物

3.1 打包 Android 产物

在工程的根目录执行以下命令进行打包:

react-native bundle \
--entry-file ./index.js \
--bundle-output ./bundle/androidBundle/index.android.bundle \
--platform android \
--assets-dest ./bundle/androidBundle \
--dev false

执行后,工程根目录 /bundle/androidBundle 下会生成 Android 产物,全选 androidBundle 下所有文件后进行压缩,得到的 zip 文件将用于上传到 Shiply。

Android 打包产物目录结构 Android 打包压缩示例

3.2 打包 iOS 产物

在工程的根目录执行以下命令进行打包:

react-native bundle \
--entry-file ./index.js \
--bundle-output ./bundle/iOSBundle/index.ios.bundle \
--platform ios \
--assets-dest ./bundle/iOSBundle \
--dev false

执行后,工程根目录 /bundle/iOSBundle 下会生成 iOS 产物,全选 iOSBundle 下所有文件后进行压缩,得到的 zip 文件将用于上传到 Shiply。

iOS 打包产物目录结构

3.3 打包 HarmonyOS 产物

在工程的根目录执行以下命令进行打包:

react-native bundle-harmony \
--entry-file ./index.js \
--bundle-output ./bundle/harmonyBundle/bundle.harmony.js \
--assets-dest ./bundle/harmonyBundle/assets \
--dev false

执行后,工程根目录 /bundle/harmonyBundle 下会生成 HarmonyOS 产物,全选 harmonyBundle 下所有文件后进行压缩,得到的 zip 文件将用于上传到 Shiply。

HarmonyOS 打包产物目录结构

四、发布 RN 动态化产物

获取到动态产物 zip 包后,即可将该 zip 包配置到发布平台进行发布,并由 SDK 自动下载安装,并在合适的时机加载生效。

发布平台的使用可参考 《平台使用指引》

这篇文档对您有帮助吗?