如何在原生鴻蒙APP中使用RN的bundle包
一、創(chuàng)作背景
上一篇博客中,我給大家分享了如何創(chuàng)建一個(gè)RN的項(xiàng)目,并且解決了其中的問(wèn)題點(diǎn),成功打出了Bundle包。接下來(lái)就是我給大家分享一下,如何在原生鴻蒙項(xiàng)目中使用那個(gè)Bundle包,這一篇分享完才算是開(kāi)發(fā)環(huán)境真正的搭建好了。
在本篇中,我將繼續(xù)分享環(huán)境搭建中會(huì)遇到的坑點(diǎn),幫助大家快速搭建成功。
二、搭建鴻蒙原生RN的原生項(xiàng)目部分
1、創(chuàng)建一個(gè)普通的鴻蒙原生項(xiàng)目
2、復(fù)制鴻蒙tgz包到項(xiàng)目中
在RN項(xiàng)目最外層新建2個(gè)文件夾,分別為react-native-harmony以及react-native-harmony-cli。然后將鴻蒙的相應(yīng)這2個(gè)tgz包分別放入相應(yīng)文件夾中,目錄層級(jí)大概是這樣子:
3、關(guān)聯(lián)鴻蒙tgz文件
打開(kāi)package.json,在dependencies中關(guān)聯(lián)上前面新建的tgz包
4、關(guān)聯(lián)openharmony包
在鴻蒙項(xiàng)目的根目錄中,新建一個(gè)libs文件夾。
將官方提供的openharmony包復(fù)制進(jìn)去,如下圖。
接下來(lái)修改一下原生項(xiàng)目的oh-package.json文件,關(guān)聯(lián)一下剛剛復(fù)制進(jìn)去的openharmony包。
5、安裝鴻蒙所需的依賴
打開(kāi)命令行,進(jìn)入原生項(xiàng)目的根目錄,運(yùn)行ohpm install命令。
如果報(bào)下面的錯(cuò)誤,說(shuō)明上一步,關(guān)聯(lián)包有問(wèn)題,找不到包:
如果安裝依賴成功,命令行會(huì)是下面這樣子:
此時(shí)進(jìn)入鴻蒙原生項(xiàng)目中查看,會(huì)發(fā)現(xiàn)多了ohpm_module的文件夾:
6、補(bǔ)充C++側(cè)代碼
- 在
MyApplication/entry/src/main目錄下新建 cpp 文件夾。 - 在 cpp 目錄下新增
CMakeLists.txt,并將 RNOH 的適配層代碼添加到編譯構(gòu)建中生成librnoh_app.so:project(rnapp) cmake_minimum_required(VERSION 3.4.1) set(CMAKE_SKIP_BUILD_RPATH TRUE) set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules") set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(RNOH_CPP_DIR "${OH_MODULE_DIR}/@rnoh/react-native-openharmony/src/main/cpp") set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated") set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments") set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie") add_compile_definitions(WITH_HITRACE_SYSTRACE) set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use add_subdirectory("${RNOH_CPP_DIR}" ./rn) add_library(rnoh_app SHARED "./PackageProvider.cpp" "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp" ) target_link_libraries(rnoh_app PUBLIC rnoh) - 在 cpp 目錄下新增
PackageProvider.cpp,將以下代碼直接復(fù)制進(jìn)去即可#include "RNOH/PackageProvider.h" using namespace rnoh; std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) { return {}; } - 打開(kāi)
MyApplicaton\entry\build-profile.json5,將以下代碼直接復(fù)制進(jìn)去即可:{ "apiType": "stageMode", "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + } }, "buildOptionSet": [ { "name": "release", "arkOptions": { "obfuscation": { "ruleOptions": { "enable": true, "files": [ "./obfuscation-rules.txt" ] } } } }, ], "targets": [ { "name": "default" }, { "name": "ohosTest", } ] }
7、補(bǔ)充arkts側(cè)代碼
- 打開(kāi)
MyApplicaton\entry\src\main\ets\entryability\EntryAbility.ets,之前默認(rèn)是繼承自UIAbility,這里要改成繼承RNAbility。并且需要重寫(xiě)getPagePath,返回程序的入口 page。import { RNAbility } from '@rnoh/react-native-openharmony'; export default class EntryAbility extends RNAbility { getPagePath() { return 'pages/Index'; } } - 在
MyApplicaton\entry\src\main\ets目錄下新增RNPackagesFactory.ets,把以下代碼復(fù)制進(jìn)去即可:import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts'; export function createRNPackages(ctx: RNPackageContext): RNPackage[] { return []; } - 打開(kāi)
MyApplicaton\entry\src\main\ets\pages\Index.ets,添加RNOH的使用代碼,修改后如下:
import {
AnyJSBundleProvider,
ComponentBuilderContext,
FileJSBundleProvider,
MetroJSBundleProvider,
ResourceJSBundleProvider,
RNApp,
RNOHErrorDialog,
RNOHLogger,
TraceJSBundleProviderDecorator,
RNOHCoreContext
} from '@rnoh/react-native-openharmony';
import { createRNPackages } from '../RNPackagesFactory';
@Builder
export function buildCustomRNComponent(ctx: ComponentBuilderContext) {}
const wrappedCustomRNComponentBuilder = wrapBuilder(buildCustomRNComponent)
@Entry
@Component
struct Index {
@StorageLink('RNOHCoreContext') private rnohCoreContext: RNOHCoreContext | undefined = undefined
@State shouldShow: boolean = false
private logger!: RNOHLogger
aboutToAppear() {
this.logger = this.rnohCoreContext!.logger.clone("Index")
const stopTracing = this.logger.clone("aboutToAppear").startTracing();
this.shouldShow = true
stopTracing();
}
onBackPress(): boolean | undefined {
// NOTE: this is required since `Ability`'s `onBackPressed` function always
// terminates or puts the app in the background, but we want Ark to ignore it completely
// when handled by RN
this.rnohCoreContext!.dispatchBackPress()
return true
}
build() {
Column() {
if (this.rnohCoreContext && this.shouldShow) {
if (this.rnohCoreContext?.isDebugModeEnabled) {
RNOHErrorDialog({ ctx: this.rnohCoreContext })
}
RNApp({
rnInstanceConfig: {
createRNPackages,
enableNDKTextMeasuring: true, // 該項(xiàng)必須為true,用于開(kāi)啟NDK文本測(cè)算
enableBackgroundExecutor: false,
enableCAPIArchitecture: true, // 該項(xiàng)必須為true,用于開(kāi)啟CAPI
arkTsComponentNames: []
},
initialProps: { "foo": "bar" } as Record<string, string>,
appKey: "AwesomeProject",
wrappedCustomRNComponentBuilder: wrappedCustomRNComponentBuilder,
onSetUp: (rnInstance) => {
rnInstance.enableFeatureFlag("ENABLE_RN_INSTANCE_CLEAN_UP")
},
jsBundleProvider: new TraceJSBundleProviderDecorator(
new AnyJSBundleProvider([
new MetroJSBundleProvider(),
// NOTE: to load the bundle from file, place it in
// `/data/app/el2/100/base/com.rnoh.tester/files/bundle.harmony.js`
// on your device. The path mismatch is due to app sandboxing on HarmonyOS
new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'),
new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'hermes_bundle.hbc'),
new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js')
]),
this.rnohCoreContext.logger),
})
}
}
.height('100%')
.width('100%')
}
}
8、復(fù)制RN生成的業(yè)務(wù)bundle到項(xiàng)目中
將之前RN那邊生成的bundle 文件和 assets 圖片放在 entry/src/main/resources/rawfile 路徑下,由于上一步我們?cè)诖a中設(shè)置了從rawfile下面獲取,所以就能加載到這個(gè)目錄。
9、重新編譯項(xiàng)目依賴
上面已經(jīng)把鴻蒙的RN相關(guān)依賴都配置好了,接下來(lái)進(jìn)入DevEco Studio,選擇File->Sync and Refresh Project選項(xiàng),編譯器會(huì)把前面設(shè)置的依賴都加載進(jìn)編譯器的內(nèi)存。
10、構(gòu)建和運(yùn)行項(xiàng)目
點(diǎn)擊運(yùn)行按鈕即可。接下來(lái)就是摘取勝利果實(shí)的時(shí)候了,也是最容易出現(xiàn)問(wèn)題的時(shí)候。我會(huì)將其中可能出現(xiàn)的問(wèn)題,列舉出來(lái)分享出來(lái)給大家。
問(wèn)題一 沒(méi)有配置cmakelist
如果你沒(méi)有配置cmakelist或者配置不正確,將會(huì)報(bào)如下錯(cuò)誤:
解決方案:詳見(jiàn)步驟6,新建cpp文件,將配置代碼復(fù)制進(jìn)入即可。
問(wèn)題二 項(xiàng)目路徑太長(zhǎng)
如果你的項(xiàng)目路徑名字太長(zhǎng),獲取文件夾放得太深,導(dǎo)致整個(gè)路徑超過(guò)260個(gè)字符,也會(huì)編譯不過(guò),具體報(bào)錯(cuò)信息如下:
解決方案:將項(xiàng)目路徑放淺一些,然后路徑里每個(gè)文件夾名字都改簡(jiǎn)單一些。
問(wèn)題三 Ability繼承錯(cuò)誤
你想使用RN的那個(gè)Ability需要繼承自RNAbility,如果你忘記改了,繼續(xù)繼承UIAbility的話,那么就會(huì)報(bào)一下錯(cuò)誤:
解決方案:參考步驟7,修改繼承的父類即可。
問(wèn)題四 鴻蒙依賴錯(cuò)誤
如果你的cpp環(huán)境沒(méi)有配置好,或者是沒(méi)有把包復(fù)制到前面說(shuō)過(guò)的目錄下,就會(huì)報(bào)這個(gè)錯(cuò)誤:
解決方案:參考步驟6,配置好cpp相關(guān)依賴。
問(wèn)題五 官方DEMO方法名錯(cuò)誤
如果你是直接下載的官方DEMO,運(yùn)行的時(shí)候會(huì)報(bào)這個(gè)方法找不到的錯(cuò)誤。
解決方案:這個(gè)是官方DEMO自帶的問(wèn)題,把報(bào)錯(cuò)的地方instance->callFunction改成instance->callJSFunction即可。
三、本文總結(jié)
在本文中,我分享了如何搭建鴻蒙原生這邊的環(huán)境,可以讓RN那邊打出來(lái)的bundle包跑起來(lái)。同時(shí)列出來(lái)了很多大家都很容易碰到的問(wèn)題,并且給出了對(duì)應(yīng)解決方案,希望能對(duì)大家有所幫助。
接下來(lái),我將分享RN在鴻蒙端的熱加載和調(diào)試配置,以及分享其中的踩坑點(diǎn),感興趣的家人們可以點(diǎn)贊關(guān)注一下。文中有表達(dá)錯(cuò)誤的地方,也歡迎大家批評(píng)指正,共同進(jìn)步。

本文中,我分享了如何讓RN那邊打出來(lái)的bundle包跑起來(lái),同時(shí)列出來(lái)了很多大家都很容易碰到的問(wèn)題
浙公網(wǎng)安備 33010602011771號(hào)