From 176558a161608db1523706b697d323f6f694205a Mon Sep 17 00:00:00 2001 From: hzjzwcu <1127781044@qq.com> Date: Mon, 15 Apr 2024 17:13:39 +0800 Subject: [PATCH] =?UTF-8?q?[Issues:=20#I9GT6J]=20TurboModule=E8=AE=BF?= =?UTF-8?q?=E9=97=AEJS=E7=8E=AF=E5=A2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + _sidebar.md | 1 + zh-cn/AccessingJSFromTurboModule.md | 112 ++++++++++++++++++++++++++++ zh-cn/README.md | 1 + 4 files changed, 115 insertions(+) create mode 100644 zh-cn/AccessingJSFromTurboModule.md diff --git a/README.md b/README.md index 0fed008..48b54e7 100644 --- a/README.md +++ b/README.md @@ -47,3 +47,4 @@ - [常见问题 Q&A](/zh-cn/qa.md) - [AutoLink](/zh-cn/autolink.md) + - [TurboModule访问JS环境](zh-cn/AccessingJSFromTurboModule.md) diff --git a/_sidebar.md b/_sidebar.md index fec99f9..56c874d 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -40,3 +40,4 @@ - [常见问题 Q&A](zh-cn/qa.md) - [AutoLink](zh-cn/autolink.md) + - [TurboModule访问JS环境](zh-cn/AccessingJSFromTurboModule.md) diff --git a/zh-cn/AccessingJSFromTurboModule.md b/zh-cn/AccessingJSFromTurboModule.md new file mode 100644 index 0000000..42ba74f --- /dev/null +++ b/zh-cn/AccessingJSFromTurboModule.md @@ -0,0 +1,112 @@ +# TurboModule访问JS环境 + +## 背景说明 + +在适配鸿蒙时,React Native(RN)的第三方库通常会涉及到C++代码的编写。除了使用Arkts重新实现接口外,也可以直接复用原有的函数接口,这大大减少了工作量。详细信息可参考RN新架构[文档说明](https://github.com/reactwg/react-native-new-architecture/discussions/160)。 + +## 调用C++代码 + +要直接复用代码,首先需要查看原始库的引用方式。如果是调用C++代码,那么在鸿蒙侧也可以采用相同的方式来复用代码。以 **[react-native-worklets-core](https://github.com/react-native-oh-library/react-native-worklets-core)** 为例,原始库中大量使用了C++代码,在`WKTJsiWorkletApi.h`中定义了一个函数`installApi`,使用方法如下: + +- IOS + + 在`Worklets.mm`代码中直接混用C++代码: + + ```c++ + // 引用接口 + #import "WKTJsiWorkletApi.h" + // 调用接口 + RNWorklet::JsiWorkletApi::installApi(*runtime); + ``` + +- Android + + 在`cpp-adapter.cpp`适配器文件中直接引用C++函数: + + ```c++ + // 引用接口 + #include "WKTJsiWorkletApi.h" + // 调用接口 + RNWorklet::JsiWorkletApi::installApi(*jsiRuntime); + ``` + +- Harmony + + 在`TurboModule`文件中直接引用C++函数,例如`WorkletsTurboModule.cpp`: + + ```c++ + // 引入接口 + #include "WKTJsiWorkletApi.h" + // 调用接口 + RNWorklet::JsiWorkletApi::installApi(rt); + ``` + + > 在RN的新架构中,`WorkletsTurboModule.cpp`往往只是利用`callAsync`或者`call`调用TS接口,作为原生组件方法的桥接。但也可以像上述代码一样直接运行外部的函数逻辑,不需要在TS中额外再写一遍。 + +## 访问和处理JS运行时上下文 + +在直接调用C++函数时,可能需要传入一些参数: + +- `runtime`:这是一个参数,类型为 `facebook::jsi::Runtime &rt`,表示JavaScript执行环境的运行时。在React Native中,JavaScript代码在Native代码中执行,而`runtime`代表了JavaScript的执行环境,它提供了与JavaScript交互的接口,比如创建对象、调用函数等。 +- `jsInvoker`:用于将传入的函数异步调度到JavaScript环境中执行。例如,通过 `jsInvoker->invokeAsync(std::move(f))` 的方式将任务发送给JavaScript环境中的事件队列,等待JavaScript执行环境空闲时执行。 + +示例代码如下: + +- IOS + + 在`Worklets.mm`中,关键代码如下: + + ```c++ + RCTCxxBridge *cxxBridge = (RCTCxxBridge *)_bridge; + auto callInvoker = cxxBridge.jsCallInvoker; + facebook::jsi::Runtime *jsRuntime = (facebook::jsi::Runtime *)cxxBridge.runtime; + ``` + +- Android + + 在`cpp-adapter.cpp`适配器文件中,引入是在Java的原生代码中,例如`WorkletsModule.java`,关键代码如下: + + ```java + WeakReference weakReactContext = new WeakReference<>(context); + ReactApplicationContext context = weakReactContext.get(); + long jsiRuntimeRef = context.getJavaScriptContextHolder().get(); + CallInvokerHolder jsCallInvokerHolder = context.getCatalystInstance().getJSCallInvokerHolder(); + ``` + +- Harmony + + 例如`WorkletsTurboModule.cpp`, `runtime`参数是在模块初始化的过程中从JavaScript运行时传入的,可以在TurboModule中直接使用,无需显式地传递或定义。完整示例代码如下: + + ```c++ + #include "WorkletsTurboModule.h" + #include "RNOH/ArkTSTurboModule.h" + #include "WKTJsiWorkletApi.h" + + using namespace rnoh; + using namespace facebook; + + namespace rnoh { + jsi::Value install(facebook::jsi::Runtime &rt, react::TurboModule &turboModule, const facebook::jsi::Value *args, + size_t count) + { + auto self = static_cast(&turboModule); + self->install(rt); + return true; + } + + RNCWorkletsTurboModule::RNCWorkletsTurboModule(const ArkTSTurboModule::Context ctx, const std::string name) + : ArkTSTurboModule(ctx, name) + { + methodMap_ = {{"install", {0, rnoh::install}}}; + } + + void RNCWorkletsTurboModule::install(facebook::jsi::Runtime &rt) + { + auto jsInvoker = this->jsInvoker_; + RNWorklet::JsiWorkletContext::getDefaultInstance()->initialize( + "default", &rt, [=](std::function &&f) { jsInvoker->invokeAsync(std::move(f)); }); + + RNWorklet::JsiWorkletApi::installApi(rt); + } + } // namespace rnoh + ``` \ No newline at end of file diff --git a/zh-cn/README.md b/zh-cn/README.md index 0fed008..48b54e7 100644 --- a/zh-cn/README.md +++ b/zh-cn/README.md @@ -47,3 +47,4 @@ - [常见问题 Q&A](/zh-cn/qa.md) - [AutoLink](/zh-cn/autolink.md) + - [TurboModule访问JS环境](zh-cn/AccessingJSFromTurboModule.md) -- Gitee