RN适配鸿蒙踩坑日记(一)

2,849 阅读2分钟

前言

由于项目需求,组件需要支持 iOSAndroidHarmonyOS 三端,碰巧 React Native (RN) 的鸿蒙适配开源了,所以决定尝试使用 RN 来开发三端 App。这份踩坑日记记录了在适配 HarmonyOS 过程中遇到的问题和解决方法,供大家参考。

环境搭建以及项目初始化

环境搭建和项目初始化过程相对简单,按照 ohos_react_native 的官方文档可以顺利完成。

第三方插件的适配

起初,使用了 @react-native-oh-tpl/react-native-gesture-handler@react-native-oh-tpl/react-native-safe-area-context@react-native-oh-tpl/stack 等库。这些库的适配较好,可以参考 官方文档进行使用。

然而,在集成 @react-native-oh-tpl/react-native-doc-viewer 这个库时,出现了问题。

问题

首先,根据文档执行了以下操作:

// 三方适配的库都是要指定版本的,在制定版本上fork改造的
npm i react-native-doc-viewer@2.7.8

接着,安装鸿蒙适配版本的类库:

// 根据自己tgz包的文件来改
npm i  @react-native-oh-tpl/react-native-doc-viewer@file:../react-native-harmony-packages/react-native-oh-tpl-react-native-doc-viewer-2.7.8-0.0.2.tgz

在代码中尝试调用库的方法:

const handlePreview = async () => {
    if (Platform.OS === 'ios') {
      //IOS
      OpenFile.openDoc(
        [
          {
            url: 'https://xxxxxxxx',
            fileNameOptional: 'test',
          },
        ],
        (error, url) => {
          if (error) {
            console.error(error);
          } else {
            console.log(url);
          }
        },
      );
    } else {
      //Android
      OpenFile.openDoc(
        [
          {
            url: 'https://xxxxxxxx', // Local "file://" + filepath
            fileName: 'test',
            cache: false,
            fileType: 'pptx',
          },
        ],
        (error, url) => {
          if (error) {
            console.error(error);
          } else {
            console.log(url);
          }
        },
      );
    }
  };

然而,满怀期待打开 App 后,却发现那经典的一幕: Uncaught Error TurboModuleRegistry.getEnforcing(...):'RNCDocViewercould not be found. Verify that a module by this name isregistered in the native binary

Screenshot_2024-11-08T155725.png

解决方法

经过一番源码分析和对 ohos_react_native 的文档研究,发现该库仅适配了 TurboModule,但缺乏 cxxTurboModule 的适配代码。因此,我们需要手动为 cxxTurboModule 进行适配。

@react-native-oh-tpl/react-native-doc-viewer/src 目录下创建 cpp 文件夹,并添加以下文件:

  1. DocViewerTurboModule.h
#pragma once
#include "RNOH/ArkTSTurboModule.h"

namespace rnoh {
class JSI_EXPORT DocViewerTurboModule : public ArkTSTurboModule {
public:
    DocViewerTurboModule(const ArkTSTurboModule::Context ctx, const std::string name);
};
}
  1. DocViewerTurboModule.cpp
#include "DocViewerTurboModule.h"
#include "RNOH/ArkTSTurboModule.h"

using namespace rnoh;
using namespace facebook;

static jsi::Value __hostFunction_DocViewerTurboModule_openDoc(jsi::Runtime &rt, react::TurboModule &turboModule,
                                                              const jsi::Value *args, size_t count) {
    return jsi::Value(static_cast<ArkTSTurboModule &>(turboModule).call(rt, "openDoc", args, count));
}

// 其他方法定义省略...

DocViewerTurboModule::DocViewerTurboModule(const ArkTSTurboModule::Context ctx, const std::string name)
    : ArkTSTurboModule(ctx, name) {
    methodMap_["openDoc"] = MethodMetadata{0, __hostFunction_DocViewerTurboModule_openDoc};
}
  1. DocViewerPackage.h
#include "RNOH/Package.h"
#include "DocViewerTurboModule.h"

namespace rnoh {
class DocViewerPackage : public Package {
public:
    DocViewerPackage(Package::Context ctx) : Package(ctx) {}
    std::unique_ptr<TurboModuleFactoryDelegate> createTurboModuleFactoryDelegate() override {
        return std::make_unique<NativeRTCDocViewerFactoryDelegate>();
    }
};
}
  1. CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)

file(GLOB rnoh_doc_viewer_SRC CONFIGURE_DEPENDS *.cpp)
add_library(rnoh_doc_viewer SHARED ${rnoh_doc_viewer_SRC})
target_include_directories(rnoh_doc_viewer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(rnoh_doc_viewer PUBLIC rnoh)

更新鸿蒙工程配置

在鸿蒙工程的 CMakeLists.txt 中添加:

add_subdirectory("类库cpp文件夹路径" ./doc-viewer)
target_link_libraries(rnoh_app PUBLIC rnoh_doc_viewer)

并在 PackageProvider.cpp 中增加以下代码:

#include "DocViewerPackage.h"
using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return { 
    // 增加的代码
    std::make_shared<DocViewerPackage>(ctx) 
    };
}

至此,问题解决,成功适配了 @react-native-oh-tpl/react-native-doc-viewer 到 HarmonyOS。

效果

Screenshot_2024-11-08T162516.png

最后

放上我对这个库的pr