c++iosobjective-creact-nativereact-native-jsi

React Native JSI: How to call any javascript function from native?


I need to have a callback function to listen for some events in native module and transfers data from native to javascript and I want to call this javascript function from native directly in React Native iOS app without sending events to NativeEventEmitter.

How to implement this with JSI (JavaScript Interface)?


Solution

  • First, your function must be defined globally in javascript e.g.:

    App.js

    global.greeting = function(param) {
        return "Hello " + param + "!";
    };
    

    Then you should find and call it with React Native Runtime in native:

    AppDelegate.mm

    #include <jsi/jsi.h>
    #import <React/RCTBridge+Private.h>
    
    using namespace facebook::jsi;
    using namespace std;
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
      ...
      
      // Runtime notification
      [NSNotificationCenter.defaultCenter addObserverForName:RCTJavaScriptDidLoadNotification object:nil queue:nil
                                                  usingBlock:^(NSNotification* notification) {
        // Get runtime
        RCTCxxBridge* cxxbridge = (RCTCxxBridge*)notification.userInfo[@"bridge"];
        if (cxxbridge.runtime) {
          Runtime& runtime = *(Runtime*)cxxbridge.runtime;
          
          // Get global function
          Function greeting = runtime.global().getPropertyAsFunction(runtime, "greeting");
          
          // Call with param
          Value param = Value(runtime, String::createFromUtf8(runtime, "JSI"));
          Value result = greeting.call(runtime, move(param), 1);
          
          string str = result.asString(runtime).utf8(runtime);
          printf("Result: %s", str.c_str());
        }
      }];
      return YES;
    }
    

    Outputs:

    Result: Hello JSI!
    

    Note: Since the sample uses JSI for synchronous native methods access, remote debugging (e.g. with Chrome) is no longer possible. Instead, you should use Flipper for debugging your JS code.