[ReactNative笔记]my-mod适配JSI

219 阅读1分钟

准备环境

  • volta
$ volta ls
⚡️ Currently active tools:

    Node: v16.20.2 (default)
    Yarn: v1.22.19 (default)
    Tool binaries available:
        nrm (default)
  • nrm
$ nrm ls
* npm ---------- https://registry.npmjs.org/
  yarn --------- https://registry.yarnpkg.com/
  tencent ------ https://mirrors.cloud.tencent.com/npm/
  cnpm --------- https://r.cnpmjs.org/
  taobao ------- https://registry.npmmirror.com/
  npmMirror ---- https://skimdb.npmjs.com/registry/
  • react-native
$ npx react-native info
...
  react-native:
    installed: 0.72.6
...
  • create-react-native-library
$ npx create-react-native-library --version
0.34.2

创建my-mod

  • 创建my-mod
$ npx create-react-native-library my-mod
✔ What is the name of the npm package? … react-native-my-mod
✔ What is the description for the package? … My module with C++
✔ What is the name of package author? … Sunbreak
✔ What is the email address for the package author? … sunbreak.wang@gmail.com
✔ What is the URL for the package author? … https://github.com/Sunbreak
✔ What is the URL for the repository? … https://github.com/Sunbreak/react-native-my-mod
✔ What type of library do you want to develop? › Native module
✔ Which languages do you want to use? › C++ for Android & iOS
✔ Project created successfully at my-mod!
  • 初始化my-mod
$ cd my-mod
$ yarn
  • Android运行my-mod
$ yarn example start &
$ yarn example android
  • iOS运行my-mode
$ yarn example start &
$ yarn example ios

origin-nojsi.png

适配JSI

适配JS/TS

  • 修改index.tsx
export function multiply(a: number, b: number): number {
  return global.multiply(a, b);
}
  • 修改App.tsx
-export default function App() {
-  const [result, setResult] = React.useState<number | undefined>();
+const result = multiply(3, 7);

-  React.useEffect(() => {
-    multiply(3, 7).then(setResult);
-  }, []);
+export default function App() {

适配C++

  • 修改react-native-my-mod.h
 #ifndef MYMOD_H
 #define MYMOD_H

+#include "jsi/jsi.h"
+
 namespace mymod {
-  double multiply(double a, double b);
+
+void install(facebook::jsi::Runtime &runtime);
+
 }

 #endif /* MYMOD_H */
  • 修改react-native-my-mod.cpp
#include "react-native-my-mod.h"

using namespace facebook::jsi;

namespace mymod {

void install(Runtime &runtime) {
    runtime.global().setProperty(
        runtime,
        "multiply",
        Function::createFromHostFunction(
            runtime,
            PropNameID::forAscii(runtime, "multiply"),
            2,
            [](Runtime &rt, const Value &thisVal, const Value *args, size_t count) -> Value {
                double a = args[0].getNumber();
                double b = args[1].getNumber();
                return { a * b };
            }
        )
    );
}

}

适配Android

  • 修改build.gradle
  defaultConfig {
     ...
     externalNativeBuild {
       cmake {
+        arguments "-DANDROID_STL=c++_shared"
         cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all"
         abiFilters "x86", "x86_64", "armeabi-v7a", "arm64-v8a"
       }
     }
   }

+  packagingOptions {
+    exclude "**/libjsi.so"
+  }
+
+  buildFeatures {
+    prefab true
+  }
  • 修改CMakelists.txt
cmake_minimum_required(VERSION 3.13)

set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_CXX_STANDARD 17)

# Define the library name here.
project(cpp)

find_package(ReactAndroid REQUIRED CONFIG)

add_library(${CMAKE_PROJECT_NAME}
    SHARED
        ../cpp/react-native-my-mod.cpp
        cpp-adapter.cpp
)

# Specifies a path to native header files.
target_include_directories(${CMAKE_PROJECT_NAME}
    PRIVATE
        ../cpp
)

target_link_libraries(${CMAKE_PROJECT_NAME}
        ReactAndroid::jsi
)
  • 修改cpp-adapter.cpp
#include "react-native-my-mod.h"

 extern "C"
-JNIEXPORT jdouble JNICALL
-Java_com_mymod_MyModModule_nativeMultiply(JNIEnv *env, jclass type, jdouble a, jdouble b) {
-    return mymod::multiply(a, b);
+JNIEXPORT void JNICALL
+Java_com_mymod_MyModModule_nativeInstall(JNIEnv *env, jclass type, jlong jsContext) {
+    auto runtime = reinterpret_cast<facebook::jsi::Runtime *>(jsContext);
+    mymod::install(*runtime);
 }
  • 修改MyModModule.java
-  private static native double nativeMultiply(double a, double b);
-
-  // Example method
-  // See https://reactnative.dev/docs/native-modules-android
-  @ReactMethod
-  public void multiply(double a, double b, Promise promise) {
-    promise.resolve(nativeMultiply(a, b));
-  }
+  public static native void nativeInstall(long jsContext);
  • 修改example/android中的MainApplication.java
         protected Boolean isHermesEnabled() {
           return BuildConfig.IS_HERMES_ENABLED;
         }
+
+        @Override
+        protected JSIModulePackage getJSIModulePackage() {
+          JSIModulePackage jsiModulePackage = super.getJSIModulePackage();
+          return (reactApplicationContext, javaScriptContextHolder) -> {
+            reactApplicationContext.getNativeModule(MyModModule.class).nativeInstall(javaScriptContextHolder.get());
+            if (jsiModulePackage != null) {
+              return jsiModulePackage.getJSIModules(reactApplicationContext, javaScriptContextHolder);
+            }
+            return new ArrayList<>();
+          };
+        }
       };

适配iOS

  • 修改MyMod.h
-#ifdef RCT_NEW_ARCH_ENABLED
-#import "RNMyModSpec.h"
-
-@interface MyMod : NSObject <NativeMyModSpec>
-#else
 #import <React/RCTBridgeModule.h>

 @interface MyMod : NSObject <RCTBridgeModule>
-#endif
  • 修改MyMod.mm
#import "MyMod.h"
#import "jsi/jsi.h"
#import <React/RCTBridge+Private.h>

using namespace facebook::jsi;

@implementation MyMod

@synthesize bridge = _bridge;

RCT_EXPORT_MODULE()

+ (BOOL)requiresMainQueueSetup {
    return YES;
}

- (void)setBridge:(RCTBridge *)bridge {
    _bridge = bridge;
    RCTCxxBridge *cxxBridge = (RCTCxxBridge *)bridge;
    Runtime &runtime = *(Runtime *)cxxBridge.runtime;
    mymod::install(runtime);
}

@end

测试适配结果

参考“创建my-mod”