怎样在原生鸿蒙APP中使用RN的bundle包

打印 上一主题 下一主题

主题 817|帖子 817|积分 2451

一、创作背景

上一篇博客中,我给大家分享了怎样创建一个RN的项目,并且解决了其中的问题点,成功打出了Bundle包。接下来就是我给大家分享一下,怎样在原生鸿蒙项目中使用那个Bundle包,这一篇分享完才算是开发情况真正的搭建好了。
在本篇中,我将继续分享情况搭建中会遇到的坑点,帮助大家快速搭建成功。
二、搭建鸿蒙原生RN的原生项目部分

1、创建一个普通的鸿蒙原生项目


2、复制鸿蒙tgz包到项目中

在RN项目最外层新建2个文件夹,分别为react-native-harmony以及react-native-harmony-cli。然后将鸿蒙的相应这2个tgz包分别放入相应文件夹中,目录层级大概是如许子:

3、关联鸿蒙tgz文件

打开package.json,在dependencies中关联上前面新建的tgz包

4、关联openharmony包

在鸿蒙项目的根目录中,新建一个libs文件夹。

将官方提供的openharmony包复制进去,如下图。

接下来修改一下原生项目的oh-package.json文件,关联一下刚刚复制进去的openharmony包。

5、安装鸿蒙所需的依靠

打开命令行,进入原生项目的根目录,运行ohpm install命令。
如果报下面的错误,说明上一步,关联包有问题,找不到包:

如果安装依靠成功,命令行会是下面如许子:

此时进入鸿蒙原生项目中查看,会发现多了ohpm_module的文件夹:

6、补充C++侧代码


  • 在 MyApplication/entry/src/main 目录下新建 cpp 文件夹。
  • 在 cpp 目录下新增 CMakeLists.txt,并将 RNOH 的适配层代码添加到编译构建中天生 librnoh_app.so:
    1. project(rnapp)
    2. cmake_minimum_required(VERSION 3.4.1)
    3. set(CMAKE_SKIP_BUILD_RPATH TRUE)
    4. set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
    5. set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
    6. set(RNOH_CPP_DIR "${OH_MODULE_DIR}/@rnoh/react-native-openharmony/src/main/cpp")
    7. set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated")
    8. set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
    9. set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
    10. add_compile_definitions(WITH_HITRACE_SYSTRACE)
    11. set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use
    12. add_subdirectory("${RNOH_CPP_DIR}" ./rn)
    13. add_library(rnoh_app SHARED
    14.     "./PackageProvider.cpp"
    15.     "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
    16. )
    17. target_link_libraries(rnoh_app PUBLIC rnoh)
    复制代码
  • 在 cpp 目录下新增 PackageProvider.cpp,将以下代码直接复制进去即可
    1. #include "RNOH/PackageProvider.h"
    2. using namespace rnoh;
    3. std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    4.     return {};
    5. }
    复制代码
  • 打开 MyApplicaton\entry\build-profile.json5,将以下代码直接复制进去即可:
    1. {
    2. "apiType": "stageMode",
    3. "buildOption": {
    4. +   "externalNativeOptions": {
    5. +      "path": "./src/main/cpp/CMakeLists.txt",
    6. +      "arguments": "",
    7. +      "cppFlags": "",
    8. +    }
    9. },
    10. "buildOptionSet": [
    11.    {
    12.      "name": "release",
    13.      "arkOptions": {
    14.        "obfuscation": {
    15.          "ruleOptions": {
    16.            "enable": true,
    17.            "files": [
    18.              "./obfuscation-rules.txt"
    19.            ]
    20.          }
    21.        }
    22.      }
    23.    },
    24. ],
    25. "targets": [
    26.    {
    27.      "name": "default"
    28.    },
    29.    {
    30.      "name": "ohosTest",
    31.    }
    32. ]
    33. }
    复制代码
7、补充arkts侧代码


  • 打开 MyApplicaton\entry\src\main\ets\entryability\EntryAbility.ets,之前默认是继承自UIAbility,这里要改成继承RNAbility。并且需要重写 getPagePath,返回程序的入口 page。
    1. import { RNAbility } from '@rnoh/react-native-openharmony';
    2. export default class EntryAbility extends RNAbility {
    3.   getPagePath() {
    4.     return 'pages/Index';
    5.   }
    6. }
    复制代码
  • 在 MyApplicaton\entry\src\main\ets 目录下新增 RNPackagesFactory.ets,把以下代码复制进去即可:
    1. import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';
    2. export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
    3.   return [];
    4. }
    复制代码
  • 打开MyApplicaton\entry\src\main\ets\pages\Index.ets,添加RNOH的使用代码,修改后如下:
  1. import {
  2.   AnyJSBundleProvider,
  3.   ComponentBuilderContext,
  4.   FileJSBundleProvider,
  5.   MetroJSBundleProvider,
  6.   ResourceJSBundleProvider,
  7.   RNApp,
  8.   RNOHErrorDialog,
  9.   RNOHLogger,
  10.   TraceJSBundleProviderDecorator,
  11.   RNOHCoreContext
  12. } from '@rnoh/react-native-openharmony';
  13. import { createRNPackages } from '../RNPackagesFactory';
  14. @Builder
  15. export function buildCustomRNComponent(ctx: ComponentBuilderContext) {}
  16. const wrappedCustomRNComponentBuilder = wrapBuilder(buildCustomRNComponent)
  17. @Entry
  18. @Component
  19. struct Index {
  20.   @StorageLink('RNOHCoreContext') private rnohCoreContext: RNOHCoreContext | undefined = undefined
  21.   @State shouldShow: boolean = false
  22.   private logger!: RNOHLogger
  23.   aboutToAppear() {
  24.     this.logger = this.rnohCoreContext!.logger.clone("Index")
  25.     const stopTracing = this.logger.clone("aboutToAppear").startTracing();
  26.     this.shouldShow = true
  27.     stopTracing();
  28.   }
  29.   onBackPress(): boolean | undefined {
  30.     // NOTE: this is required since `Ability`'s `onBackPressed` function always
  31.     // terminates or puts the app in the background, but we want Ark to ignore it completely
  32.     // when handled by RN
  33.     this.rnohCoreContext!.dispatchBackPress()
  34.     return true
  35.   }
  36.   build() {
  37.     Column() {
  38.       if (this.rnohCoreContext && this.shouldShow) {
  39.         if (this.rnohCoreContext?.isDebugModeEnabled) {
  40.           RNOHErrorDialog({ ctx: this.rnohCoreContext })
  41.         }
  42.         RNApp({
  43.           rnInstanceConfig: {
  44.             createRNPackages,
  45.             enableNDKTextMeasuring: true, // 该项必须为true,用于开启NDK文本测算
  46.             enableBackgroundExecutor: false,
  47.             enableCAPIArchitecture: true, // 该项必须为true,用于开启CAPI
  48.             arkTsComponentNames: []
  49.           },
  50.           initialProps: { "foo": "bar" } as Record<string, string>,
  51.           appKey: "AwesomeProject",
  52.           wrappedCustomRNComponentBuilder: wrappedCustomRNComponentBuilder,
  53.           onSetUp: (rnInstance) => {
  54.             rnInstance.enableFeatureFlag("ENABLE_RN_INSTANCE_CLEAN_UP")
  55.           },
  56.           jsBundleProvider: new TraceJSBundleProviderDecorator(
  57.             new AnyJSBundleProvider([
  58.               new MetroJSBundleProvider(),
  59.               // NOTE: to load the bundle from file, place it in
  60.               // `/data/app/el2/100/base/com.rnoh.tester/files/bundle.harmony.js`
  61.               // on your device. The path mismatch is due to app sandboxing on HarmonyOS
  62.               new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'),
  63.               new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'hermes_bundle.hbc'),
  64.               new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js')
  65.             ]),
  66.             this.rnohCoreContext.logger),
  67.         })
  68.       }
  69.     }
  70.     .height('100%')
  71.     .width('100%')
  72.   }
  73. }
复制代码
8、复制RN天生的业务bundle到项目中

将之前RN那边天生的bundle 文件和 assets 图片放在 entry/src/main/resources/rawfile 路径下,由于上一步我们在代码中设置了从rawfile下面获取,以是就能加载到这个目录。

9、重新编译项目依靠

上面已经把鸿蒙的RN相干依靠都设置好了,接下来进入DevEco Studio,选择File->Sync and Refresh Project选项,编译器会把前面设置的依靠都加载进编译器的内存。

10、构建和运行项目

点击运行按钮即可。接下来就是摘取胜利果实的时候了,也是最容易出现问题的时候。我会将其中可能出现的问题,枚举出来分享出来给大家。
问题一  没有设置cmakelist

如果你没有设置cmakelist大概设置不正确,将会报如下错误:

解决方案:详见步调6,新建cpp文件,将设置代码复制进入即可。
问题二  项目路径太长

如果你的项目路径名字太长,获取文件夹放得太深,导致整个路径超过260个字符,也会编译不外,详细报错信息如下:

解决方案:将项目路径放浅一些,然后路径里每个文件夹名字都改简单一些。
问题三  Ability继承错误

你想使用RN的那个Ability需要继承自RNAbility,如果你忘记改了,继续继承UIAbility的话,那么就会报一下错误:

解决方案:参考步调7,修改继承的父类即可。
问题四  鸿蒙依靠错误

如果你的cpp情况没有设置好,大概是没有把包复制到前面说过的目录下,就会报这个错误:

解决方案:参考步调6,设置好cpp相干依靠。
问题五  官方DEMO方法名错误

如果你是直接下载的官方DEMO,运行的时候会报这个方法找不到的错误。

解决方案:这个是官方DEMO自带的问题,把报错的地方instance->callFunction改成instance->callJSFunction即可。

三、本文总结

在本文中,我分享了怎样搭建鸿蒙原生这边的情况,可以让RN那边打出来的bundle包跑起来。同时列出来了很多大家都很容易碰到的问题,并且给出了对应解决方案,希望能对大家有所帮助。
接下来,我将分享RN在鸿蒙端的热加载和调试设置,以及分享其中的踩坑点,感爱好的家人们可以点赞关注一下。文中有表达错误的地方,也欢迎大家品评指正,共同进步。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

梦见你的名字

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表