目录什么是jsI JSI有什么不同 在iOS中使用JSI ioS端配置 RN端配置 js调用带参数的原生方法 原生调用JS 原生调用带参数的JS方法 在原生端调用js的函数参数 总结
React Native JSI (javascript Interface) 可以使 JavaScript 和 原生模块 更快、更简单的通信。它也是React Native 新的架构体系中Fabric UI层 和 Turbo 模块的核心部分。
JSI 移除了原生代码和JavaScript代码之间的桥接(bridge),同时也省去了两端相互调用时大量的JSON序列化和反序列化操作。JSI为原生和JS交互打开了新的大门。下面是一些JSI的特点:
下面我们将一步一步的在iOS工程中使用JSI实现原生与JS的通信。
创建一个新的React Native 项目
npx react-native init jsiDemo
在iOS项目目录中创建C++文件,example.h、 example.cpp。
example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
namespace facebook {
namespace jsi {
class Runtime;
}
}
namespace example {
void install(facebook::jsi::Runtime &jsiRuntime);
}
#endif
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) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
[self installLibrary];
});
return;
}
example::install(*(facebook::jsi::Runtime *)cxxBridge.runtime);
}
@end
在 setBridge 方法中,我们调用了 example的 install 方法,完成方法的注册。
修改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;
点击按钮之后,发现result的值为helloworld。
结果
上面我们实现了js 调用原生,但没有参数,接下来我们实现一个单参数的调用。
我们在example.cpp 的 install 方法中增加multiply方法的注册,从arguments 中取出入参。
auto multiply = Function::createFromHostFunction(jsiRuntime,
PropNameID::forAscii(jsiRuntime,
"multiply"),
2,
[](Runtime &runtime,
const Value &thisValue,
const Value *arguments,
size_t count) -> Value {
int x = arguments[0].getNumber();
int y = arguments[1].getNumber();
return Value(x * y);
});
jsiRuntime.global().setProperty(jsiRuntime, "multiply", move(multiply));
然后修改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.multiply(2, 2));
};
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>{'2*2 = ' + result}</Text>
</View>
);
};
export default App;
结果
原生调用js主要通过jsiRuntime.global().getPropertyAsFunction(jsiRuntime, "jsMethod").call(jsiRuntime);方法实现。
首先我们在js中增加一个js方法。我们修改App.js 在上面增加jsMethod 方法。
import React from 'react';
import type {Node} from 'react';
import {Text, View, Button} from 'react-native';
const App: () => Node = () => {
const [result, setResult] = React.useState();
global.jsMethod = () => {
alert('hello jsMethod');
};
const press = () => {
setResult(global.multiply(2, 2));
};
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>{'2*2 = ' + result}</Text>
</View>
);
};
export default App;
在原生端,我们假设在进入应用的时候触发调用js方法,我们修改AppDelegate中的applicationWillEnterForeground 方法。
- (void)applicationWillEnterForeground:(UIApplication *)application {
SimpleJsi *jsi = [self.bridge moduleForName:@"SimpleJsi"];
[jsi calljs];
}
通过moduleForName方法获取SimpleJsi对象, 然后通过SimpleJsi中的calljs 方法。
- (void)calljs {
RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
Runtime &jsiRuntime = *(facebook::jsi::Runtime *)cxxBridge.runtime;
jsiRuntime.global().getPropertyAsFunction(jsiRuntime, "jsMethod").call(jsiRuntime);
}
结果
多参数调用和无参调用类似,只是在call方法后面增加了参数列表。
首先我们先在js侧定义方法,修改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();
global.jsMethod = () => {
alert('hello jsMethod');
};
global.jsMultiply = (x, y) => {
alert('x * y = ' + x * y);
};
const press = () => {
setResult(global.multiply(2, 2));
};
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>{'2*2 = ' + result}</Text>
</View>
);
};
export default App;
然后我们修改原生端的调用
AppDelegate.m
- (void)applicationWillEnterForeground:(UIApplication *)application {
SimpleJsi *jsi = [self.bridge moduleForName:@"SimpleJsi"];
// [jsi calljs];
[jsi callJsMultiply:4 y:4];
}
SimpleJsi.m
- (void)callJsMultiply:(int)x y:(int) y {
RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
Runtime &jsiRuntime = *(facebook::jsi::Runtime *)cxxBridge.runtime;
jsiRuntime.global().getPropertyAsFunction(jsiRuntime, "jsMultiply").call(jsiRuntime, x, y);
}
结果
在原生中调用js参数中的函数,需要通过arguments[i].getObject(runtime).getFunction(runtime).call(runtime, value);
的方式触发。
首先我们在example.cpp 中新注册一个方法multiplyWithCallback
auto multiplyWithCallback = Function::createFromHostFunction(jsiRuntime,
PropNameID::forAscii(jsiRuntime,
"multiplyWithCallback"),
3,
[](Runtime &runtime,
const Value &thisValue,
const Value *arguments,
size_t count) -> Value {
int x = arguments[0].getNumber();
int y = arguments[1].getNumber();
//调用callback
arguments[2].getObject(runtime).getFunction(runtime).call(runtime, x * y);
return Value();
});
jsiRuntime.global().setProperty(jsiRuntime, "multiplyWithCallback", move(multiplyWithCallback));
在js侧进行调用, 修改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();
global.jsMethod = () => {
alert('hello jsMethod');
};
global.jsMultiply = (x, y) => {
alert('x * y = ' + x * y);
};
const press = () => {
// setResult(global.multiply(2, 2));
global.multiplyWithCallback(4, 5, alertResult);
};
const alertResult = res => {
alert(res);
};
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>{'2*2 = ' + result}</Text>
</View>
);
};
export default App;
点击按钮之后,会调用multiplyWithCallback 将alertResult 方式传递给原生。
结果
上面就是本文对JSI 的介绍,文中的代码,你可以在公众号回复 JSI 获取GitHub 下载地址。
在RN Debug的情况下,global.xx 无法找到对应的方法,个人也没有头绪,如果你有方法解决,请联系我,非常感谢。
https://blog.notesnook.com/getting-started-react-native-jsi/
reactnative.maxieewong.com/
Https://github.com/react-native-commUnity/discussions-and-proposals/issues/91
ospfranco.com/
到此这篇关于React Native JSI实现RN与原生通信的示例代码的文章就介绍到这了,更多相关React Native原生通信内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: React Native JSI实现RN与原生通信的示例代码
本文链接: https://lsjlt.com/news/133359.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-01-12
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0