Native JSI实现RN与原生通信的示例代码 React

React,Native,JSI实现RN与原生通信的示例代码,博智网带你了解详细信息 。
目录

  • 什么是JSI
  • JSI有什么不同
  • 在iOS中使用JSI
    • iOS端配置
    • RN端配置
    • js调用带参数的原生方法
    • 原生调用JS
    • 原生调用带参数的JS方法
    • 在原生端调用js的函数参数
  • 总结
    • 问题
  • 参考资料

    什么是JSI
    React Native JSI (JavaScript Interface) 可以使 JavaScript 和 原生模块 更快、更简单的通信 。它也是React Native 新的架构体系中Fabric UI层 和 Turbo 模块的核心部分 。

    JSI有什么不同
    JSI 移除了原生代码和JavaScript代码之间的桥接(bridge),同时也省去了两端相互调用时大量的JSON序列化和反序列化操作 。JSI为原生和JS交互打开了新的大门 。下面是一些JSI的特点:
    1. JavaScript Interface 允许我们向JavaScript 运行时注册方法 。这些方法在js环境中可以通过 global对象获取并调用 。
    2. 我们完全可以使用C++或者在iOS里使用OC,在Android里使用Java实现这些注册方法 。
    3. 原先使用bridge 的方式实现的原生模块可以通过增加一层C++,快速转化为通过JSI实现 。
    4. 在iOS端实现非常简单,因为C++和OC 可以方便的实现混编 。
    5. 在Android中,我们需要通过JNI 做一些转化 。
    6. 这些方法可以是完全同步的,这意味着不必强制使用async 。await 。

    在iOS中使用JSI
    下面我们将一步一步的在iOS工程中使用JSI实现原生与JS的通信 。
    创建一个新的React Native 项目
    npx react-native init jsiDemo
    iOS端配置
    在iOS项目目录中创建C++文件,example.h、 example.cpp 。
    example.h
    #ifndef EXAMPLE_H#define EXAMPLE_Hnamespace facebook { namespace jsi {class Runtime; }}namespace example { void install(facebook::jsi::Runtime &jsiRuntime);}#endif /* EXAMPLE_H */example.m#include "example.h"#include <jsi/jsi.h>using namespace facebook::jsi;using namespace std;namespace example { void install(Runtime &jsiRuntime) {auto helloWorld = Function::createFromHostFunction(jsiRuntime,PropNameID::forAscii(jsiRuntime,"helloWorld"),0,[](Runtime &runtime,const Value &thisValue,const Value *arguments,size_t count) -> Value {string helloworld = "helloworld";return Value(runtime, String::createFromUtf8(runtime,helloworld));});jsiRuntime.global().setProperty(jsiRuntime, "helloWorld", move(helloWorld));}}
    在上面的代码中,我们使用 createFromHostFunction 方法创建了一个方法,并通过setProperty 方法将其注册到js运行时 。
    接下来,我们需要创建一个moudle, 在moudle中执行install 方法 。
    我们创建OC 文件,SimpleJsi.h,SimpleJsi.mm
    SimpleJsi.h
    #import <React/RCTBridgeModule.h>@interface SimpleJsi : NSObject <RCTBridgeModule>@property (nonatomic, assign) BOOL setBridgeOnMainQueue;@end
    SimpleJsi.mm
    #import "SimpleJsi.h"#import <React/RCTBridge+Private.h>#import <React/RCTUtils.h>#import <jsi/jsi.h>#import "example.h"#import <sys/utsname.h>using namespace facebook::jsi;using namespace std;@implementation SimpleJsi@synthesize bridge = _bridge;@synthesize methodQueue = _methodQueue;RCT_EXPORT_MODULE()+ (BOOL)requiresMainQueueSetup {return YES;}- (void)setBridge:(RCTBridge *)bridge {_bridge = bridge;_setBridgeOnMainQueue = RCTIsMainQueue();[self installLibrary];}- (void)installLibrary {RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;if (!cxxBridge.runtime) {/*** This is a workaround to install library* as soon as runtime becomes available and is* not recommended. If you see random crashes in iOS* global.xxx not found etc. use this.*/dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC),dispatch_get_main_queue(), ^{/**When refreshing the app while debugging, the setBridgemethod is called too soon. The runtime is not ready yetquite often. We need to install library as soon as runtimebecomes available.*/[self installLibrary];});return;}example::install(*(facebook::jsi::Runtime *)cxxBridge.runtime);}@end
    在 setBridge 方法中,我们调用了 example的 install 方法,完成方法的注册 。

    RN端配置
    修改App.js
    import React from 'react';import type {Node} from 'react';import {Text, View, Button} from 'react-native';const App: () => Node = () => {const [result, setResult] = React.useState();const press = () => {setResult(global.helloWorld());};return (// eslint-disable-next-line react-native/no-inline-styles<View style={{backgroundColor: '#FFFFFF', height: '100%'}}><View style={{height: '10%'}} /><Button onPress={press} title="按钮" /><Text>{'调用helloword:' + result}</Text></View>);};export default App;

    推荐阅读