[ReactNative笔记]Turbo Module原理解析——Android Spec

547 阅读1分钟

0.70官方文档:reactnative.dev/docs/0.70/t…

  • Schema
{
  "modules": {
    "NativeTurboOnly": {
      "type": "NativeModule",
      "aliases": {},
      "spec": {
        "properties": [
          {
            "name": "multiply",
            "optional": false,
            "typeAnnotation": {
              "type": "FunctionTypeAnnotation",
              "returnTypeAnnotation": {
                "type": "NumberTypeAnnotation"
              },
              "params": [
                {
                  "name": "a",
                  "optional": false,
                  "typeAnnotation": {
                    "type": "NumberTypeAnnotation"
                  }
                },
                {
                  "name": "b",
                  "optional": false,
                  "typeAnnotation": {
                    "type": "NumberTypeAnnotation"
                  }
                }
              ]
            }
          }
        ]
      },
      "moduleNames": [
        "TurboOnly"
      ]
    }
  }
}

Android library codegen

$ tree ${NODE_MODULES}/${LIBRARY}/android/build/generated/source/codegen
├── java
│   └── com
│       └── turboonly
│           └── NativeTurboOnlySpec.java
├── jni
│   ├── Android.mk
│   ├── CMakeLists.txt
│   ├── RNTurboOnlySpec-generated.cpp
│   ├── RNTurboOnlySpec.h
│   └── react
│       └── renderer
│           └── components
│               └── RNMyModSpec
│                   ├── RNTurboOnlySpecJSI-generated.cpp
│                   └── RNTurboOnlySpecJSI.h
└── schema.json

Turbo版本的BaseJavaModule

NativeTurboOnlySpec.java

$ tree ${NODE_MODULES}/${LIBRARY}/android
├── build
│   └── generated
│       └── source
│           └── codegen
│               └── java
│                   └── com
│                       └── turboonly
│                           └── NativeTurboOnlySpec.java
└── build.gradle
  • turbo-only通过library codegen的NativeTurboOnlySpec.java
public abstract class NativeTurboOnlySpec extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule {
  @ReactMethod(isBlockingSynchronousMethod = true)
  @DoNotStrip
  public abstract double multiply(double a, double b);
}
android {
  sourceSets {
    main {
      if (isNewArchitectureEnabled()) {
          java.srcDirs += [
            // This is needed to build Kotlin project with NewArch enabled
            "${project.buildDir}/generated/source/codegen/java"
          ]
      }
    }
  }
}

RNTurboOnlySpec.h/cpp

$ tree ${NODE_MODULES}/${LIBRARY}/android
└── build
    └── generated
        └── source
            └── codegen
                └── jni
                    ├── Android.mk
                    ├── CMakeLists.txt
                    ├── RNTurboOnlySpec-generated.cpp
                    └── RNTurboOnlySpec.h
  • turbo-only通过library codegen的RNTurboOnlySpec-generated.cpp
#include "RNTurboOnlySpec.h"

static facebook::jsi::Value __hostFunction_NativeTurboOnlySpecJSI_multiply(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
  static jmethodID cachedMethodId = nullptr;
  return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, NumberKind, "multiply", "(DD)D", args, count, cachedMethodId);
}

NativeTurboOnlySpecJSI::NativeTurboOnlySpecJSI(const JavaTurboModule::InitParams &params)
  : JavaTurboModule(params) {
  methodMap_["multiply"] = MethodMetadata {2, __hostFunction_NativeTurboOnlySpecJSI_multiply};
}

std::shared_ptr<TurboModule> RNTurboOnlySpec_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params) {
  if (moduleName == "TurboOnly") {
    return std::make_shared<NativeTurboOnlySpecJSI>(params);
  }
  return nullptr;
}

Turbo版本的CxxModuleWrapper

参考[ReactNative笔记]my-mod适配legecy TurboCxxModule

不依赖library codegen,底层使用TurboCxxModule.h/cpp转义folly::dynamic和jsi::Value

pure TurboCxxModule

参考[ReactNative笔记]my-mod适配pure TurboCxxModule

$ tree ${NODE_MODULES}/${LIBRARY}/android/build/generated/source/codegen
└── jni
    └── react
        └── renderer
            └── components
                └── RNMyModSpec
                    ├── RNTurboOnlySpecJSI-generated.cpp
                    └── RNTurboOnlySpecJSI.h
  • react-native-my-mod.h
#include "RNMyModSpecJSI.h"

class MyModCxxModule : public NativeMyModCxxSpecJSI {
 public:
  MyModCxxModule(std::shared_ptr<CallInvoker> jsInvoker);

  void multiply(Runtime &rt, double a, double b, Function callback) override;
};
  • MainModuleManagerDelegate.cpp
#include <react-native-my-mod.h>

std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
    const std::string &name,
    const std::shared_ptr<CallInvoker> &jsInvoker) {
  if (name == "MyMod") {
    return std::make_shared<mymod::MyModCxxModule>(jsInvoker);
  }

  // Not implemented yet: provide pure-C++ NativeModules here.
  return nullptr;
}

std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
    const std::string &name,
    const JavaTurboModule::InitParams &params) {
  return MainApplicationModuleProvider(name, params);
}

Android APP Autolink

0.70的CMakeLists.txt

0.70的library官方文档:reactnative.dev/docs/0.70/n…

0.70的APP官方文档:reactnative.dev/docs/0.70/n…

$ tree ${APP}/android/app
├── build
│   └── generated
│       └── rncli
│           └── src
│               └── main
│                   └── jni
│                       ├── Android-rncli.cmake
│                       ├── Android-rncli.mk
│                       ├── rncli.cpp
│                       └── rncli.h
├── build.gradle
└── src
    └── main
        └── jni
            └── CMakeLists.txt
graph TD
    subgraph example
        build.gradle --> app-cmake[CMakeLists.txt]
        Android-rncli.cmake
    end
    app-cmake --> ReactNative-application.cmake --> Android-rncli.cmake
    ReactNative-application.cmake --> Android-prebuilt.cmake
    subgraph turbo-only
        lib-cmake[CMakeLists.txt]
    end
    Android-rncli.cmake --> lib-cmake
add_subdirectory(/Users/sunbreak/w/Sunbreak/reactnative-turbo.trial/turbo-only/android/build/generated/source/codegen/jni/ RNTurboOnlySpec_autolinked_build)

set(AUTOLINKED_LIBRARIES 
  react_codegen_RNTurboOnlySpec
)

0.69的Android.mk

0.69的library官方文档:reactnative-archive-august-2023.netlify.app/docs/0.69/n…

0.69的APP官方文档:reactnative-archive-august-2023.netlify.app/docs/0.69/n…

react-native@0.69.x使用@react-native-community/cli@8.x,Autolink仅生成PackageList.java,没有Android-rncli.mk

$ tree ${APP}/android/app
├── build.gradle
└── src
    └── main
        └── jni
            └── Android.mk
graph TD
    subgraph APP
        build.gradle --> app-mk[Android.mk]
    end
    app-mk --> Android-prebuilt.mk
    subgraph library
        lib-mk[Android.mk]
    end

TurboModuleManager调用链路

Application启动

graph TD
    onCreate --> useTurboModules[useTurboModules = true]
    subgraph MainApplication
        onCreate
    end
    onCreate --> getReactInstanceManager
    subgraph MainApplicationReactNativeHost
        getReactInstanceManager --> createReactInstanceManager --> getReactPackageTurboModuleManagerDelegateBuilder
        getReactPackageTurboModuleManagerDelegateBuilder
    end
    getReactPackageTurboModuleManagerDelegateBuilder --> Builder
    subgraph MainApplicationTurboModuleManagerDelegate
        Builder
    end

Activity启动

graph LR
    subgraph MainActivity
        act-onCreate[onCreate]
    end
    act-onCreate --> dlg-onCreate
    subgraph MainActivityDelegate
        dlg-onCreate[onCreate] --> actdlg-loadApp[loadApp]
    end
    actdlg-loadApp --> dlg-loadApp
    subgraph ReactDelegate
        dlg-loadApp[loadApp]
    end
    dlg-loadApp --> startReactApplication
    subgraph ReactRootView
        startReactApplication
    end
    startReactApplication --> createReactContextInBackground
    subgraph ReactInstanceManager
        createReactContextInBackground
    end
  • TurboModuleManager初始化
graph TD
    createReactContextInBackground --> recreateReactContextInBackgroundInner
    recreateReactContextInBackgroundInner --> recreateReactContextInBackgroundFromBundleLoader
recreateReactContextInBackgroundFromBundleLoader --> recreateReactContextInBackground
    recreateReactContextInBackground --> runCreateReactContextOnNewThread
    runCreateReactContextOnNewThread --> createReactContext
  private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
    ...
    if (ReactFeatureFlags.useTurboModules && mTMMDelegateBuilder != null) {
      TurboModuleManagerDelegate tmmDelegate =
          mTMMDelegateBuilder
              .setPackages(mPackages)
              .setReactApplicationContext(reactContext)
              .build();

      TurboModuleManager turboModuleManager =
          new TurboModuleManager(
              catalystInstance.getRuntimeExecutor(),
              tmmDelegate,
              catalystInstance.getJSCallInvokerHolder(),
              catalystInstance.getNativeCallInvokerHolder());

      catalystInstance.setTurboModuleManager(turboModuleManager);

      TurboModuleRegistry registry = (TurboModuleRegistry) turboModuleManager;

      // Eagerly initialize TurboModules
      for (String moduleName : registry.getEagerInitModuleNames()) {
        registry.getModule(moduleName);
      }
    }
    ...
  }

找到needsEagerInit的TurboModule

graph LR
    subgraph TurboModuleManager
        mgr-getEagerInitModuleNames[getEagerInitModuleNames]
    end
    mgr-getEagerInitModuleNames --> dlg-getEagerInitModuleNames
    subgraph ReactPackageTurboModuleManagerDelegate
        dlg-getEagerInitModuleNames[getEagerInitModuleNames]
    end
  @Override
  public List<String> getEagerInitModuleNames() {
    List<String> moduleNames = new ArrayList<>();
    for (TurboReactPackage reactPackage : mPackages) {
      for (ReactModuleInfo moduleInfo :
          reactPackage.getReactModuleInfoProvider().getReactModuleInfos().values()) {

        if (moduleInfo.isTurboModule() && moduleInfo.needsEagerInit()) {
          moduleNames.add(moduleInfo.name());
        }
      }
    }
    return moduleNames;
  }

TurboModuleManager初始化

生成provider绑定proxy

graph TD
    subgraph TurboModuleBinding.cpp
        install -..->|build| jsProxy
    end
    installJSIBindings --> install
    jsProxy --> turboModuleProvider
    subgraph TurboModuleManager.cpp
        installJSIBindings -..->|build| turboModuleProvider
    end

provider生成TurboModule.cpp

  • 调用链
graph TD
    subgraph TurboModuleManager
        subgraph mgr-cpp
            turboModuleProvider
        end
        subgraph mgr-java
                    getJavaModule
        getLegecyCxxModule
        end
    end
    turboModuleProvider --> getLegecyCxxModule -..->|CxxModuleWrapper.java| wrp-getModule
    turboModuleProvider --> wrp-getModule
    subgraph CxxModuleWrapper.cpp
        wrp-getModule([getModule])
    end
    turboModuleProvider --> getTurboModule-js
    turboModuleProvider --> getTurboModule-java
    turboModuleProvider --> getJavaModule -..->|TurboModule.java| getTurboModule-java
    subgraph MainModuleManagerDelegate.cpp
        getTurboModule-js(["getTurboModule(jsInvoker)"])
        getTurboModule-java(["getTurboModule(javaParams)"])
    end
    wrp-getModule -..->|cxxModule| ctor-cxx
    turboModuleProvider --> ctor-cxx
    subgraph TurboCxxModule.cpp
        ctor-cxx(["TurboCxxModule(jsInvoker)"])
    end
    getTurboModule-java --> ctor-java
    subgraph JavaTurboModule.cpp
        ctor-java(["JavaTurboModule(javaParams)"])
    end
  • 管理类图
classDiagram
    class mgrJava["TurboModuleManager.java"] {
        -delegate
        +getEagerInitModuleNames()
        +getLegecyCxxModule()
        +getJavaModule()
        -installJSIBindings()
    }
    mgrJava <|.. mgrCpp: Composition
    class mgrCpp["TurboModuleManager.cpp"] {
        -delegate_
        -installJSIBindings()
    }
    mgrDlgJava .. mgrJava
    class mgrDlgJava["TurboModuleManagerDelegate.java"] {
        +getModule()*
        +getLegecyCxxModule()*
        +getEagerInitModuleNames()
    }
    mgrDlgJava <|.. mgrDlgCpp: Composition
    mgrDlgCpp .. mgrCpp
    class mgrDlgCpp["TurboModuleManagerDelegate.cpp"] {
        +getTurboModule(jsInvoker)*
        +getTurboModule(javaParams)*
    }
    mgrDlgJava <|-- rctMgrDlgJava
    class rctMgrDlgJava["ReactPackageTurboModuleManagerDelegate.java"] {
        +getModule()
        +getLegecyCxxModule()
        -resolveModule()
        +getEagerInitModuleNames()
    }
    rctMgrDlgJava <|-- mainMgrDlgJava
    class mainMgrDlgJava["MainModuleManagerDelegate.java"] {
        -canCreateTurboModule()
    }
    mainMgrDlgJava <|.. mainMgrDlgCpp: Composition
    mgrDlgCpp <|-- mainMgrDlgCpp
    class mainMgrDlgCpp["MainModuleManagerDelegate.cpp"] {
        +getTurboModule(jsInvoker)
        +getTurboModule(javaParams)
        -canCreateTurboModule()
    }
  • 数据类图
classDiagram
    wrpBaseJava <|.. wrpBaseCpp: Composition
    class wrpBaseJava["CxxModuleWrapperBase.java"] {
        +getName()
    }
    class wrpBaseCpp["CxxModuleWrapperBase.cpp"] {
        +getName()*
        +getModule()*
    }
    wrpJava <|.. wrpCpp: Composition
    wrpBaseJava <|-- wrpJava
    class wrpJava["CxxModuleWrapper.java"] {
        +makeDsoNative()$
    }
    wrpBaseCpp <|-- wrpCpp
    class wrpCpp["CxxModuleWrapper.cpp"] {
        +makeDsoNative()$
        +getName()
        +getModule(): CxxModule
    }
    CxxModule .. wrpCpp
    CxxModule .. TurboCxxModule
    class CxxModule["CxxModule.cpp"]
    class jsi_HostObject["jsi::HostObject.cpp"] {
        +get(propName)*
    }
    jsi_HostObject <|-- TurboModule
    class TurboModule["TurboModule.cpp"] {
        +get(propName)*
    }
    TurboModule <|-- TurboCxxModule
    class TurboCxxModule["TurboCxxModule.cpp"] {
        -cxxModule_: CxxModule
        +get(propName)*
        +invokeMethod()
    }
    TurboModule <|-- JavaTurboModule
    class JavaTurboModule["JavaTurboModule.cpp"] {
        -instance_: JTurboModule
        +JavaTurboModule(javaParams)
        +invokeJavaMethod()
    }
    JTurboModule .. JavaTurboModule
    class JTurboModule["JTurboModule.cpp"]
    class TurboModuleJava["TurboModule.java"]
    TurboModuleJava <|.. JTurboModule: Composition
    

provider搜索TurboModule.java

graph TD
    subgraph TurboModuleManager
        subgraph mgr-java
            getJavaModule --> mgr-getModule
            getLegecyCxxModule --> mgr-getModule[getModule]
            mgr-getModule([getModule]) --> getOrCreateModule
        end
        subgraph mgr-cpp
            turboModuleProvider
        end
        turboModuleProvider --> getJavaModule
        turboModuleProvider --> getLegecyCxxModule
    end
    getOrCreateModule --> dlg-getModule
    getOrCreateModule --> dlg-getCxxModule
    subgraph ReactPackageTurboModuleManagerDelegate.java
        dlg-getModule([getModule]) --> resolveModule
        dlg-getCxxModule([getCxxModule]) --> resolveModule
    end
    resolveModule --> pkg-getModule
    subgraph TurboReactPackage.java
        pkg-getModule([getModule])
    end