You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native 0.66中如何获取JSCallInvoker?(MMKV二次开发)

问题:React Native 0.66(启用Hermes)中无法从RCTBridge获取JSCallInvoker

我在基于React Native 0.66(启用Hermes)二次开发react-native-mmkv库时,尝试访问React Native桥接中指向JS线程的JSCallInvoker方法,但在Xcode中找不到该方法的引用。当前通过[RCTBridge currentBridge]获取的bridge对象无法访问JSCallInvoker,想咨询是否需要添加额外头文件,或其他获取JSCallInvoker的方法。

相关代码如下:

#import "MmkvModule.h"
#import "JSIUtils.h"
#import <React/RCTBridge+Private.h>
#import <ReactCommon/CallInvoker.h>
#import <React/RCTUtils.h>
#import <jsi/jsi.h>
#import <MMKV/MMKV.h>
#import "MmkvHostObject.h"

using namespace facebook;

@implementation MmkvModule

RCT_EXPORT_MODULE(MMKV)

+ (NSString*)getPropertyAsStringOrNilFromObject:(jsi::Object&)object
                                   propertyName:(std::string)propertyName
                                        runtime:(jsi::Runtime&)runtime
{
    jsi::Value value = object.getProperty(runtime, propertyName.c_str());
    std::string string = value.isString() ? value.asString(runtime).utf8(runtime) : "";
    return string.length() > 0 ? [NSString stringWithUTF8String:string.c_str()] : nil;
}

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install:(nullable NSString*)storageDirectory)
{
    NSLog(@"Installing global.mmkvCreateNewInstance...");
    //RCTBridge
    RCTBridge* bridge = [RCTBridge currentBridge]; /// THIS VARIABLE doesnt have access to js call invoker
    
    RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge;
    if (cxxBridge == nil) {
        return @false;
    }
    
    using namespace facebook;
    
    auto jsiRuntime = (jsi::Runtime*) cxxBridge.runtime;
    if (jsiRuntime == nil) {
        return @false;
    }
    auto& runtime = *jsiRuntime;
    RCTUnsafeExecuteOnMainQueueSync(^{
      [MMKV initializeMMKV:storageDirectory];
    });
    
    // MMKV.createNewInstance()
    auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction(runtime,
                                                                       jsi::PropNameID::forAscii(runtime, "mmkvCreateNewInstance"),
                                                                       1,
                                                                       [](jsi::Runtime& runtime,
                                                                          const jsi::Value& thisValue,
                                                                          const jsi::Value* arguments,
                                                                          size_t count) -> jsi::Value {
        if (count != 1) {
            throw jsi::JSError(runtime, "MMKV.createNewInstance(..) expects one argument (object)!");
        }
        jsi::Object config = arguments[0].asObject(runtime);
        
        NSString* instanceId = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"id" runtime:runtime];
        NSString* path = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"path" runtime:runtime];
        NSString* encryptionKey = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"encryptionKey" runtime:runtime];
        
        auto instance = std::make_shared<MmkvHostObject>(instanceId, path, encryptionKey);
        return jsi::Object::createFromHostObject(runtime, instance);
    });
    runtime.global().setProperty(runtime, "mmkvCreateNewInstance", std::move(mmkvCreateNewInstance));
    
    NSLog(@"Installed global.mmkvCreateNewInstance!");
    return @true;
}

@end

Xcode报错截图:
Xcode中无法找到JSCallInvoker引用的截图


解决方案

1. 添加私有头文件依赖

JSCallInvoker的引用在RCTCxxBridge类中,需要显式导入其头文件:

#import <React/RCTCxxBridge.h>

注:私有头文件依赖可能随RN版本迭代发生变化,但在RN 0.66版本中可稳定使用。

2. 从RCTCxxBridge直接获取JSCallInvoker

在你已将RCTBridge强转为RCTCxxBridge的基础上,直接访问jsCallInvoker属性即可:

RCTBridge* bridge = [RCTBridge currentBridge];
RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge;
if (cxxBridge == nil) {
    return @false;
}
// 获取指向JS线程的CallInvoker
std::shared_ptr<facebook::react::CallInvoker> jsCallInvoker = cxxBridge.jsCallInvoker;

3. 替代方案:通过TurboModuleManager获取

若私有头文件方式稳定性不足,可通过RCTBridge的turboModuleManager间接获取:

#import <React/RCTTurboModuleManager.h>

// ...
id<RCTTurboModuleManager> turboModuleManager = bridge.turboModuleManager;
std::shared_ptr<facebook::react::CallInvoker> jsCallInvoker = turboModuleManager.jsCallInvoker;

注:此方案需确保项目启用TurboModule,RN 0.66搭配Hermes时默认支持。

4. 修改后的完整代码示例

#import "MmkvModule.h"
#import "JSIUtils.h"
#import <React/RCTBridge+Private.h>
#import <React/RCTCxxBridge.h> // 新增头文件
#import <ReactCommon/CallInvoker.h>
#import <React/RCTUtils.h>
#import <jsi/jsi.h>
#import <MMKV/MMKV.h>
#import "MmkvHostObject.h"

using namespace facebook;

@implementation MmkvModule

RCT_EXPORT_MODULE(MMKV)

+ (NSString*)getPropertyAsStringOrNilFromObject:(jsi::Object&)object
                                   propertyName:(std::string)propertyName
                                        runtime:(jsi::Runtime&)runtime
{
    jsi::Value value = object.getProperty(runtime, propertyName.c_str());
    std::string string = value.isString() ? value.asString(runtime).utf8(runtime) : "";
    return string.length() > 0 ? [NSString stringWithUTF8String:string.c_str()] : nil;
}

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install:(nullable NSString*)storageDirectory)
{
    NSLog(@"Installing global.mmkvCreateNewInstance...");
    RCTBridge* bridge = [RCTBridge currentBridge];

    RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge;
    if (cxxBridge == nil) {
        return @false;
    }

    // 获取JSCallInvoker
    std::shared_ptr<facebook::react::CallInvoker> jsCallInvoker = cxxBridge.jsCallInvoker;
    if (!jsCallInvoker) {
        NSLog(@"Failed to retrieve JSCallInvoker");
        return @false;
    }

    auto jsiRuntime = (jsi::Runtime*) cxxBridge.runtime;
    if (jsiRuntime == nil) {
        return @false;
    }
    auto& runtime = *jsiRuntime;
    RCTUnsafeExecuteOnMainQueueSync(^{
      [MMKV initializeMMKV:storageDirectory];
    });

    // MMKV.createNewInstance()
    auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction(runtime,
                                                                       jsi::PropNameID::forAscii(runtime, "mmkvCreateNewInstance"),
                                                                       1,
                                                                       [jsCallInvoker](jsi::Runtime& runtime,
                                                                          const jsi::Value& thisValue,
                                                                          const jsi::Value* arguments,
                                                                          size_t count) -> jsi::Value {
        if (count != 1) {
            throw jsi::JSError(runtime, "MMKV.createNewInstance(..) expects one argument (object)!");
        }
        jsi::Object config = arguments[0].asObject(runtime);
        
        NSString* instanceId = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"id" runtime:runtime];
        NSString* path = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"path" runtime:runtime];
        NSString* encryptionKey = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"encryptionKey" runtime:runtime];
        
        auto instance = std::make_shared<MmkvHostObject>(instanceId, path, encryptionKey);
        return jsi::Object::createFromHostObject(runtime, instance);
    });
    runtime.global().setProperty(runtime, "mmkvCreateNewInstance", std::move(mmkvCreateNewInstance));
    
    NSLog(@"Installed global.mmkvCreateNewInstance!");
    return @true;
}

@end

内容的提问来源于stack exchange,提问作者Nitish Phanse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 12:55:18