注册

React Native JSI:将BridgeModule转换为JSIModule

我们原有的项目中有大量的使用OC或者Java编写的原生模块,其中的一些可以使用C++重写,但大多数模块使用了平台特有的API和SDK,他们没有对应的C++实现。


在本文中,将带领大家如何将原有的模块转化为JSI模块。本文不再讲解基础概念,如果你有不明白的地方请参考上一篇文章


使用JSI实现js与原生交互

上图描述了两端是如何进行交互的,这里面没有了React Native 的 Bridge,而是使用了C++作为中介。



  1. 在iOS端可以很简单的实现,因为OC和C++可以混编。
  2. 在Android端要麻烦一些,需要通过JNI进行C++ 与 Java的交互。

iOS端实现


首先我们在SimpleJsi.mm 中增加 getModelsetItemgetItem 用以模拟原生模块。这些方法都使用到了平台特有的API。


- (NSString *)getModel {

struct utsname systemInfo;

uname(&systemInfo);

return [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
}

- (void)setItem:(NSString *)key :(NSString *)value {

NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];

[standardUserDefaults setObject:value forKey:key];

[standardUserDefaults synchronize];
}

- (NSString *)getItem:(NSString *)key {

NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];

return [standardUserDefaults stringForKey:key];
}


接下来我们需要实现一个新的install方法:


static void install(facebook::jsi::Runtime &jsiRuntime, SimpleJsi *simpleJsi) {

auto getDeviceName = Function::createFromHostFunction(
jsiRuntime, PropNameID::forAscii(jsiRuntime, "getDeviceName"), 0,
[simpleJsi](Runtime &runtime, const Value &thisValue,
const Value *arguments, size_t count) -> Value {

facebook::jsi::String deviceName =
convertNSStringToJSIString(runtime, [simpleJsi getModel]);

return Value(runtime, deviceName);
});
jsiRuntime.global().setProperty(jsiRuntime, "getDeviceName", move(getDeviceName));
}

这个方法接收两个参数。其中SimpleJsi 用来调用 getModel 方法。这个方法的返回值是NSString。我们需要将其转化为JSI认识的String类型。这里我们使用了convertNSStringToJSIString 方法。这个放开来自开源代码YeetJSIUtils


然后,我们在修改RN端,修改APP.js


const press = () => {
// setResult(global.multiply(2, 2));
// global.multiplyWithCallback(4, 5, alertResult);
alert(global.getDeviceName());
};

执行结果。


执行结果

同理,我们适配一下其他两个方法。


关键的地方还是参数的获取与转换。


auto setItem = Function::createFromHostFunction(
jsiRuntime, PropNameID::forAscii(jsiRuntime, "setItem"), 2,
[simpleJsi](Runtime &runtime, const Value &thisValue,
const Value *arguments, size_t count) -> Value {
NSString *key =
convertJSIStringToNSString(runtime, arguments[0].getString(runtime));
NSString *value =
convertJSIStringToNSString(runtime, arguments[1].getString(runtime));

[simpleJsi setItem:key :value];

return Value(true);
});
jsiRuntime.global().setProperty(jsiRuntime, "setItem", move(setItem));


auto getItem = Function::createFromHostFunction(
jsiRuntime, PropNameID::forAscii(jsiRuntime, "getItem"), 0,
[simpleJsi](Runtime &runtime, const Value &thisValue,
const Value *arguments, size_t count) -> Value {

NSString *key =
convertJSIStringToNSString(runtime, arguments[0].getString(runtime));
facebook::jsi::String value =
convertNSStringToJSIString(runtime, [simpleJsi getItem:key]);

return Value(runtime, value);
});
jsiRuntime.global().setProperty(jsiRuntime, "getItem", move(getItem));

修改App.js


const press = () => {
global.setItem('RiverLi', '大前端');
setTimeout(() => {
alert(global.getItem('RiverLi'));
}, 300);
};

执行结果


image-20210816113702360

总结


使用JSI进行moudle开发虽然看着有些复杂,但还是值得我们花时间去研究的。因为它的性能是最佳的,没有不必要的转换,所有的操作都是那么直接的发生在一层上。





作者:RiverLi
链接:https://juejin.cn/post/6999799689155444773

0 个评论

要回复文章请先登录注册