RN新架构

907 阅读3分钟

一、为什么要新架构

因为现有架构有性能问题,具体如下:

  1. JS 层与 Native 的通讯依赖 Bridge转发
  2. Bridge转发通过线程切换传递JSON数据,并在单个工作线程内接收
  3. 滑动、动画等场景下高度计算、更新等高频UI变动使Bridge拥塞
  4. 界面出现白屏或卡顿

二、怎么做的

构建新的通信层,具体分为JSI、TurboModule、Fabric

  1. JSI
  • 标准通信设施层,对旧架构Bridge的替代

    • JS直连C++ Native层
      • 旧架构有nativeLog这类函数也是直连,但是仅是部分函数实现,且依赖JavaScriptCore,不是整个通信设施层
    • JSRuntime标准化,可选替代V8、Hermes
  • API 调用流程(以Android平台JS向JAVA的单向通信为例)

    • 旧架构:JS->Bridge->JAVA
    • 新架构:JS->JSI->C++->JNI->JAVA
  1. TurboModule
  • 原生模块通信层,对旧架构NativeModule(官方文档上Native Modules这一节)的替代
  • 通过JSI设施,完成原生模块定义和管理,让JS可调用原生模块,包括内置的、第三方原生库和应用侧自定义原生模块
  1. Fabric
  • 原生UI通信层,对旧架构ViewManager(官方文档上Native Components这一节)的替代
  • 通过JSI设施,完成原生UI的定义和管理,所定义出的UI模块,可在JSX使用

三、JSI示例

通过上面的简述,可以看到JSI是基础,已在0.60支持,旧架构下的三方库都可以通过它改造,完成直连。

github.com/craftzdog/r…

  1. 原生能力的实现:在base64.h中定义,base64.cpp中实现,如base64_encode函数
// base64.h,函数声明

std::string base64_encode     (std::string const& s, bool url = false);
  1. 原生能力安装入口:react-native-quick-base64.cpp
// cpp/react-native-quick-base64.cpp

// 安装函数,会在收集模块时被调用,完成原生能力的定义

void installBase64(jsi::Runtime& jsiRuntime) {

  std::cout << "Initializing react-native-quick-base64" << "\n";



  // 通过JSI提供的jsi::Function::createFromHostFunction创建可注入对象

  auto base64FromArrayBuffer = jsi::Function::createFromHostFunction(

      jsiRuntime,

      jsi::PropNameID::forAscii(jsiRuntime, "base64FromArrayBuffer"),

      1,  // string

      [](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value {

        std::string str;

        if(!valueToString(runtime, arguments[0], &str)) {

          return jsi::Value(-1);

        }

        // 实际的能力调用

        std::string strBase64 = base64_encode(str);



        // 前后做一些参数转换

        return jsi::Value(jsi::String::createFromUtf8(runtime, strBase64));

      }

  );

  // 将base64FromArrayBuffer注入到JSRuntime

  // 此后在JS环境下,有一个叫base64FromArrayBuffer能在JS下使用

  jsiRuntime.global().setProperty(jsiRuntime, "base64FromArrayBuffer", std::move(base64FromArrayBuffer));



...//后面还导出了一个base64ToArrayBuffer
  1. 初始化的时候安装:通过JNI提供到JAVA层,由JAVA层完成安装动作
// android/cpp-adapter.cpp JNI层提供QuickBase64Module_initialize到JAVA

extern "C"

JNIEXPORT void JNICALL

Java_com_reactnativequickbase64_QuickBase64Module_initialize(JNIEnv* env, jclass clazz, jlong jsiPtr) {

  installBase64(*reinterpret_cast<facebook::jsi::Runtime*>(jsiPtr));

}



// android/src/main/java/com/reactnativequickbase64/QuickBase64Module.java

private static native void initialize(long jsiPtr, String docDir);



@Override

public void initialize() {

super.initialize();



// 模块初始化的时候完成初始化安装

QuickBase64Module.initialize(

  this.getReactApplicationContext().getJavaScriptContextHolder().get(),

  this.getReactApplicationContext().getFilesDir().getAbsolutePath());

}
  1. JS上的使用
// src/index.tsx

// 作为JS层函数fromByteArray导出给应用侧使用

export function fromByteArray(uint8: Uint8Array): string {

  // 通过jsiRuntime.global().setProperty注入的base64FromArrayBuffer已在global可用

  return base64FromArrayBuffer(uint8.buffer);

}



// 作为JS层函数btoa导出给应用侧使用

export function btoa(data: string): string {

  return base64FromArrayBuffer(stringToArrayBuffer(data));

}

四、对应用侧的影响

目前看来,基本无影响,只会带来性能上的提升。

当然,三方库、自定义模块倒是需要更新才能享受新架构提升。

0.65代码库里已有JSI、TurboModule、Fabric相关代码,JSI、TurboModule已可用。

内部完全是用兼容的方式在开发,设了很多开关,可以看ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java文件,复杂性都留在了内部。

新架构从提出来到现在,已经三年多了,目前还没正式release,在线等。

原文链接:mp.weixin.qq.com/s/M81MxAdcw…