我使用 RN 0.66.3 并希望在我的 iOS React Native 项目中直接同步调用从 javascript 到本机代码以共享数据,而不使用 React Native Bridge 来提高性能,因此我需要一个共享的全局对象并访问它来自javascript的属性和方法。
我知道 JSI(JavaScript 接口)可以做到这一点,但是没有文档和很少的教程,那么实现这个的简单步骤或示例代码是什么?
我使用 RN 0.66.3 并希望在我的 iOS React Native 项目中直接同步调用从 javascript 到本机代码以共享数据,而不使用 React Native Bridge 来提高性能,因此我需要一个共享的全局对象并访问它来自javascript的属性和方法。
我知道 JSI(JavaScript 接口)可以做到这一点,但是没有文档和很少的教程,那么实现这个的简单步骤或示例代码是什么?
要通过 React Native JSI 将您的对象公开给 javascript,您应该执行以下步骤:
HostObject
get
和set
方法来实现对其属性和方法的访问。查看可以在应用程序启动期间NativeStorage
持久存储键/值对的示例:NSUserDefaults
NativeStorage 类
#include <jsi/jsi.h>
#import <React/RCTBridge+Private.h>
using namespace facebook::jsi;
using namespace std;
// Store key-value pairs persistently across launches of your app.
class NativeStorage : public HostObject {
public:
/// Stored property
int expirationTime = 60 * 60 * 24; // 1 day
// Helper function
static NSString* stringValue(Runtime &runtime, const Value &value) {
return value.isString()
? [NSString stringWithUTF8String:value.getString(runtime).utf8(runtime).c_str()]
: nil;
}
Value get(Runtime &runtime, const PropNameID &name) override {
auto methodName = name.utf8(runtime);
// `expirationTime` property getter
if (methodName == "expirationTime") {
return this->expirationTime;
}
// `setObject` method
else if (methodName == "setObject") {
return Function::createFromHostFunction(runtime, PropNameID::forAscii(runtime, "setObject"), 2,
[](Runtime &runtime, const Value &thisValue,const Value *arguments, size_t count) -> Value {
NSString* key = stringValue(runtime, arguments[0]);
NSString* value = stringValue(runtime, arguments[1]);
if (key.length && value.length) {
[NSUserDefaults.standardUserDefaults setObject:value forKey:key];
return true;
}
return false;
});
}
// `object` method
else if (methodName == "object") {
return Function::createFromHostFunction(runtime, PropNameID::forAscii(runtime, "object"), 1,
[](Runtime &runtime, const Value &thisValue,const Value *arguments, size_t count) -> Value {
NSString* key = stringValue(runtime, arguments[0]);
NSString* value = [NSUserDefaults.standardUserDefaults stringForKey:key];
return value.length
? Value(runtime, String::createFromUtf8(runtime, value.UTF8String))
: Value::undefined();
});
}
return Value::undefined();
}
void set(Runtime& runtime, const PropNameID& name, const Value& value) override {
auto methodName = name.utf8(runtime);
// ExpirationTime property setter
if (methodName == "expirationTime") {
if (value.isNumber()) {
this->expirationTime = value.asNumber();
}
}
}
// Install `nativeStorage` globally to the runtime
static void install(Runtime& runtime) {
NativeStorage nativeStorage;
shared_ptr<NativeStorage> binding = make_shared<NativeStorage>(move(nativeStorage));
auto object = Object::createFromHostObject(runtime, binding);
runtime.global().setProperty(runtime, "nativeStorage", object);
}
};
AppDelegate.mm
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
// Runtime notification
[NSNotificationCenter.defaultCenter addObserverForName:RCTJavaScriptDidLoadNotification object:nil queue:nil
usingBlock:^(NSNotification* notification) {
RCTCxxBridge* cxxbridge = (RCTCxxBridge*)notification.userInfo[@"bridge"];
if (cxxbridge.runtime) {
NativeStorage::install(*(Runtime*)cxxbridge.runtime);
}
}];
return YES;
}
应用程序.js
nativeStorage.expirationTime = 1000;
console.log(nativeStorage.expirationTime);
const key = "greeting";
nativeStorage.setObject(key, "Hello JSI!");
const text = nativeStorage.object(key);
console.log(text);
输出:
1000
Hello JSI!
Future React Native 的 TurboModules 和 CodeGen 使这一切变得更干净、更容易,但它是原生模块的低级 JSI 实现,可以直接从 JavaScript 调用,而无需通过 React Native Bridge。
注意:由于示例使用 JSI 进行同步本地方法访问,远程调试(例如使用 Chrome)不再可能。相反,您应该使用 Flipper 来调试您的 JS 代码。