Write a You.i React Native Native Module

Native modules bind native code to JavaScript, extending the functionality of your React Native application. For You.i Platform, native modules are usually written in C++.

In general, a You.i React Native native module is simply a C++ class that exposes a name, methods, and constants to the React instance within JavaScript.

There are two simple steps to create a You.i React Native native module:

  1. Create the framework.
  2. Add a constructor and other methods.

You can then follow the rest of the topics here for adding constant methods, adding callbacks, dealing with events, etc.

If your native module includes platform-specific code in Swift or Java, see the sections below for additional steps to take.

Create the Framework

Create your class starting with header using this template, replacing MyFirstModule with the name of your module:

#include <youireact/NativeModule.h>

class YI_RN_MODULE(MyFirstModule)


And the matching implementation file:

#include "MyFirstModule.h"
#include <youireact/NativeModuleRegistry.h>
#include <platform/YiDeviceBridgeLocator.h>
#include <platform/YiDeviceInformationBridge.h>


Implicitly, the getName() method is added to your module and returns the name of your module (which is specified with the macro YI_RN_EXPORT_NAME shown in the header file above).

Now you can use MyFirstModule in your application like this:

import { NativeModules } from 'react-native';

const SampleModule = NativeModules.MyFirstModule;

Add Native Module Files to Build System

You may have different native module files for each platform (for example, you may have a module that works on iOS and another that works on Android), so the build system doesn’t automatically find and build all new .cpp files when building your project.

To tell the build system to add these new files to your project, add the .cpp and .h file names to youi/SourceList.cmake as shown below, then generate the project again with youi-tv generate -p <platform>.

# =============================================================================



If needed, you can use cmake conditions or YI_PROJECT_SOURCE_* and YI_PLATFORM_UPPER variables to define exactly which files to include with each platform’s build. In the example below, myiosModule.cpp is included for iOS, mytvOSModule.cpp is included for tvOS, and nothing extra is included for any other platform.




Constructor & Methods


The native module is instantiated and the class constructor is implicitly called when your application starts.

Other Methods

You probably want your native module to expose some methods to JavaScript. To do this, use YI_RN_EXPORT_METHOD and YI_RN_DEFINE_EXPORT_METHOD in the header and class files, respectively. The basic framework from create includes an example with a method called doSomething:

// MyFirstModule.h
#include <youireact/NativeModule.h>
class YI_RN_MODULE(MyFirstModule)
// MyFirstModule.cpp
#include "MyFirstModule.h"
YI_RN_INSTANTIATE_MODULE(MyFirstModule); // this is required
YI_RN_DEFINE_EXPORT_METHOD(MyFirstModule, doSomething)()
    YI_LOGD(TAG, "Native Module Called");

From JavaScript, you can now access to the doSomething method as follows:

// native-module-sample.js
import { NativeModules } from 'react-native';

const SampleModule = NativeModules.MyFirstModule;

// Call into C++

The sample method is declared without parameters, but your native module methods can include C++ parameters. See Method Parameters for more details.

Note: Exported native module methods can’t be overloaded.

Constant Methods

To export data from native or C++ code, use constant methods. Use the YI_RN_EXPORT_CONSTANT and the YI_RN_DEFINE_EXPORT_CONSTANT macros to define your method:

// MyFirstModule.h
// MyFirstModule.cpp
YI_RN_DEFINE_EXPORT_CONSTANT(MyFirstModule, someConstants)
    return folly::dynamic::object
        ("size", folly::dynamic::object("width", 100)("height", 100))
        ("name", "Name");
// native-module-sample.js
import { NativeModules } from 'react-native';

const SampleModule = NativeModules.MyFirstModule;

// Call into C++
const size = SampleModule.someConstants.size;


Your native module can accept a JavaScript function as a callback. Imagine you want to pass in a String from JavaScript and specify a callback function to handle a returned value. Start by updating the C++ method definition:

// myNativeModule.h
#include <youireact/NativeModule.h>
class YI_RN_MODULE(NativeModuleSample)
    YI_RN_EXPORT_METHOD(doSomethingWithCallback)(Callback successCallback, Callback failedCallback, CYIString str);


And add the corresponding C++ method. Note that Callback parameters must always come first in the definition.

// myNativeModule.cpp

YI_RN_DEFINE_EXPORT_METHOD(NativeModuleSample, doSomethingWithCallback)(Callback successCallback, Callback failedCallback, CYIString str))
    YI_LOGD(TAG, "%s", str.GetData());

    // callback with ({response} after 3 seconds)
    std::shared_ptr<CYIHTTPRequest> pRequest(new CYIHTTPRequest(CYIUrl("http://httpstat.us/200?sleep=3000"),

    // always assume success callback for this example
    pRequest->NotifyResponse.Connect([successCallback, str]() {
        successCallback({ ToDynamic(str) });



In JavaScript, use this method like this:

// native-module-sample.js
import { NativeModules } from 'react-native';

const SampleModule = NativeModules.NativeModuleSample;

// Call into C++
SampleModule.doSomethingWithCallback('Thanks for all the fish')
  .then(response => {
    console.log(response); // Success callback
  }).catch( err => {
    console.log(err);      // Failure callback


To send events from C++ and listen for them in JavaScript, have your native module C++ class inherit from EventEmitterModule and use the EmitEvent() function.

From JavaScript, receive events from your module by wrapping it in or extending it from NativeEventEmitter and then adding a listener for your event by calling the addListener() function.

The interface between the two is

  • a string identifying the event; and
  • a Folly object payload, converted to a JavaScript object.

Note Failure to extend your C++ class from EventEmitterModule or wrap your JavaScript module will result in signals not being sent across the bridge. For more information, see Facebook’s documentation.

The following example sends the string I/JavaScript: Event received: Test parameter. every two seconds. Note that in this case the YI_RN_MODULE and YI_RN_INSTANTIATE_MODULE macros added by the create command are updated to expose the fact that this module emits events.

// MyEvent.h
#include <youireact/modules/EventEmitter.h>
#include <utility/YiTimer.h>

class YI_RN_MODULE(MyEvent, yi::react::EventEmitterModule), public CYISignalHandler


    void SendEvent();
    CYITimer m_eventTimer;
// MyEvent.cpp
#include "MyEvent.h"

// The name specified here is the listener you connect to from JavaScript
static const std::string MY_NAMED_EVENT = "MyNamedEvent";

YI_RN_INSTANTIATE_MODULE(MyEvent, yi::react::EventEmitterModule);


    m_eventTimer.TimedOut.Connect(*this, &MyEvent::SendEvent);

void MyEvent::SendEvent()
    EmitEvent(MY_NAMED_EVENT, folly::dynamic::object("param", "Test parameter."));

Listen for the events in index.youi.js:

import { Component } from 'react';
import { AppRegistry, NativeEventEmitter, NativeModules } from 'react-native';

const myEventEmitter = new NativeEventEmitter(NativeModules.MyEvent);

export default class YiReactApp extends Component {

  componentDidMount() {
    this.myEventSubscription = myEventEmitter.addListener("MyNamedEvent", payload =>
      console.log("Event received: " + payload.param)

  componentWillUnmount() {
    this.myEventSubscription && this.myEventSubscription.remove();

  render = () => null;

AppRegistry.registerComponent('YiReactApp', () => YiReactApp);

Running this application results in the following in the console log:

Event received: I/JavaScript: Event received: Test parameter.
Event received: I/JavaScript: Event received: Test parameter.
Event received: I/JavaScript: Event received: Test parameter.
Event received: I/JavaScript: Event received: Test parameter.

Inline Methods

If you need to inline a method rather than specify it in your implementation (.cpp) file, you must use the YI_RN_REGISTER_EXPORT_METHOD macro in the associated .cpp file.

// MyModule.h
// Implementing a method inline
class YI_RN_MODULE(MyModule)
        // method body goes here
// MyModule.cpp
#include "MyModule.h"

Method Parameters

Parameters passed from JavaScript are converted to a folly::dynamic array where each element is the left-to-right parameter from the JavaScript call. The array is made up of other folly::dynamics that may be strings, numbers, objects, arrays, and so on. We suggest you define and document your method’s parameter expectations, as you may receive anything from JavaScript.

When defining your native module method, it can look like any of the following, depending on the type of parameters it expects:

// method with no parameters
// method with n parameters
// method with n parameters and one callback
YI_RN_EXPORT_METHOD(doSomething)(folly::dynamic, Callback);
// method with n parameters and two callbacks
YI_RN_EXPORT_METHOD(doSomething)(folly::dynamic, Callback, Callback);

If you’d prefer not to use folly::dynamic, you can specify your expected parameters in the function signature. The NativeModule class tries to convert the array of folly::dynamics from JavaScript into the expected arguments of your C++ method.

For example, if using the folly::dynamic mechanism, the following JavaScript reference to a native module method results in arguments that your C++ class needs to extract and convert to the right types.

MyModule.makeNamed3dPoint("Earth", 1.0, 2.5, 3.77);

However, you could alternately define your method as shown below to have You.i Platform attempt to expand the args dynamic array into the specified types, in the expected order.

// alternate definition
YI_RN_EXPORT_METHOD(doSomething)(CYIString name, float x, float y, float z);
// if any parameter is optional, indicate
YI_RN_EXPORT_METHOD(doSomething)(CYIString name, float x, float y, folly::Optional<float> z);

When using this alternate definition method, the OnBadArgumentsPassedToMethod virtual function can be overridden to manage cases where your method doesn’t get the parameters it expects. For example, your application might respond by re-attempting a call, implementing an error handler, or alerting the user of a problem.

void NativeModuleBase::OnBadArgumentsPassedToMethod(
    std::string methodName,                                 // The name of the method that was attempted
    folly::dynamic originalArgs,                            // The original folly::dynamic array containing the args
    std::vector<FollyDynamicArgsConversionReport> reports   // Failure reports for each argument conversion attempt

The reports vector contains the same number of elements as the number of expected parameters. Each report has information about the conversion attempted, some of which may have been successful.

Note that by default, NativeModuleBase logs a diagnostic warning message.

Sub-classing a Module

Suppose you want to subclass a module to inherit all of the base’s methods and override some as follows:

// Declare a subclass native module called MySubclassModule
// derived from MyModule.
class YI_RN_MODULE(MySubclassModule, MyModule)

The first parameter to the YI_RN_MODULE macro is the name of your new module. Subsequent parameters are the base class(es). Multiple inheritance is possible, but each base class must also be defined with a YI_RN_MODULE*() macro. The inheritance access level of base classes is public.

The same set of parameters is also needed for the YI_RN_INSTANTIATE_MODULE macro in the class implementation:

// MyModule.cpp
YI_RN_INSTANTIATE_MODULE(MySubclassModule, MyModule);

Override Methods in a Subclassed Module

Override a method by re-declaring it in the subclass, as normal. Exported methods are always marked virtual, so you can even use the override specifier to mark the method as an override.

// Overriding a method in a subclass
class YI_RN_MODULE(MySubclassModule, MyModule)
    YI_RN_EXPORT_METHOD(doSomething)() override;

Bridging to Swift Code

To bridge Swift code to You.i React Native, you need to make various CMake changes. You can then bridge using Objective-C++ with You.i React Native native module macros. Do the following steps:

  1. Enable the Swift language in the CMake file

  2. Fix Compiler Flags

  3. Add additional Swift Xcode settings

  4. Glob for Swift and Objective-C++ files

  5. Create the bridge and invoke the function

Enabling the Swift Language

By default, build system CMake file is configured to compile only C, C++, and Objective C. You need to manually add Swift to the CMake file’s project language settings:

  1. Open the CMakelists.txt located at <MyApp>/youi.
  2. Find the following text in the file: project(${YI_PROJECT_NAME} LANGUAGES C CXX)
  3. Replace it with the following:


    Note You can also use the CheckLanguage CMake module to check and see if Swift is supported rather than checking for iOS, tvOS, or macOS.

Fixing Compiler Flags

By default, the CMakeLists.txt file uses target_compile_options() and check_cxx_compile_flags() to send C++ flags to the compiler. These flags are invalid for Swift compiler, swiftc. You need modify CMakeLists.txt to allow for Swift flags. Do the following steps:

  1. Locate the following lines in the CMakeLists.txt file:

       PRIVATE -Wall
          -Wno-unused-parameter # for JSExecutor header
       PRIVATE -Wno-unused-result -Wno-unused-function
  2. Replace them with the following:

    yi_configure_warnings_as_errors(TARGET ${PROJECT_NAME})
    yi_configure_compile_options(PROJECT_TARGET ${PROJECT_NAME} EXTRA_FLAGS -Wno-unused-parameter)

Adding More Swift Xcode Settings

Do the following steps to set more properties in CMake required by Swift code:

  1. Create a new file called BridgingHeader.h in your src directory:

    touch BridgingHeader.h.

    Tip While empty for this example, you can use BridgingHeader.h to expose Objective-C files to Swift. The name and location aren’t important; just adjust the following steps accordingly.

  2. Add the following in CMakelists.txt:

       set_target_properties(${PROJECT_NAME} PROPERTIES

    The previous code does the following:

    • Assigns BridgingHeader.h as the bridging header file in Xcode.
    • Allows Swift code to be compiled as a module.
    • Causes the warnings related to Swift version to be ignored. Note The particular version number of Swift and its features may vary depending on the version of Xcode you are using. In the previous example, "4.2" is appropriate for Xcode version 10.1.

Globbing for Swift and Objective-C++ Files

To add the Swift and Objective-C++ files to the list of compiled files, modify SourceList.cmake. Update the following text in the file:

  • From: file(GLOB_RECURSE YI_PROJECT_SOURCE "src/*.cpp")
  • To the following:

     file(GLOB_RECURSE _COMMON_SOURCE "src/*.cpp")
     file(GLOB_RECURSE _SWIFT_SOURCE "src/.swift" "src/.mm")
        ... # OSX specific source

Creating the Bridge and Invoking the Function

The previous steps dealt with setting up. This step deals with writing files for execution. The following procedure shows you how to test your setup by writing the files of simple example where the Swift code does a print out.

  1. Add the following basic Swift code in the src folder in a new file called Test.swift:

    import Foundation
    class TestSwift : NSObject {
      @objc class func printHello() {
        print("Hello from Swift");

    The @objc attribute marks the function to expose to Objective-C.

  2. Write the following Objective-C++ code in the src folder. This Objective-C++ code exposes the Swift code as a JavaScript module:

    1. Write the TestBridge.h file.

      #ifndef _TEST_BRIDGE_H_
      #define _TEST_BRIDGE_H_
      #include "youireact/NativeModule.h"
      class YI_RN_MODULE(TestBridgeModule)
      #endif // _TEST_BRIDGE_H_
    2. Write the TestBridge.mm file.

      #include "TestBridge.h"
      #import <SwiftTest-Swift.h>
      YI_RN_DEFINE_EXPORT_METHOD(TestBridgeModule, printHello)()
         [TestSwift printHello];

      Note that SwiftTest-Swift.h is the name of the automatically generated file, and its name follows the pattern of <CMake Target Name>-Swift.h. This is typically set with the variable YI_PROJECT_NAME, which in this example is set to SwiftTest. Register the new module in the app’s UserInit function. Replace the last line in the app’s UserInit function with the following:

      bool bSuccess = PlatformApp::UserInit();
      return bSuccess;

      Run the test by invoking the function from the JavaScript as following:

      import { NativeModules } from 'react-native';
      componentDidMount() {

Using JAR Libraries

Your build process can bring in dependencies from gradle and maven, as well as local .jar or .aar libraries, if you use the module system to bring in your own module definitions with your own build.gradle.in template (instead of the default build.gradle.in template).

With the module system, you have a file structure as follows:


The folder contains:


This content is copied into your Android project during project generation. If you do not have the previous structure and content, boilerplate versions of it are copied over from the You.i C++.

In the build.gradle.in for your app, you should see a dependency section such as the following:

dependencies {
    // Include local JAR files
    implementation fileTree(dir: "libs", include: ["*.jar"])

    implementation 'com.google.android.exoplayer:exoplayer:2.9.6'
    implementation 'com.google.android.exoplayer:extension-mediasession:2.9.6'
    implementation 'com.google.android.gms:play-services-ads:15.0.1'

    // Load unit test support libraries
    testImplementation "junit:junit:4.12"

You can alter this entry to specify a new directory that contains libraries specific to your project or app; for example:

implementation fileTree(dir: "@THIRDPARTY_LIBS@", include: ["*.jar"])

Define the variable in your app’s module definition file (YiModuleDefinition.cmake):


Bring in a new .jar artifact by placing it in the directory defined in your YiModuleDefinition.cmake file.

Once you make your changes, the generate and build processes for our app do the following:

  1. Copy over module specific files for project.
  2. Look for third-party directory.
  3. Link any artifacts found.

Third-Party Static Libraries

You may want to include a third party static library (such as an analytics library) in your native module. Start by creating a place in your project to hold the library file and associated headers.

  1. In your application’s youi folder, create a sub-folder called thirdparty (or another name, if you prefer).
  2. Inside that folder, create a sub-folder for the third party library you’re including.
  3. Inside the library folder, create an include folder to hold the header files for the library.

    Your folder tree looks like this: *appname* > youi > thirdparty > *libname* >include.

  4. Place the library file in *appname* > youi > thirdparty > *libname*.
  5. Copy the associated header files into *appname* > youi > thirdparty > *libname* > include.

    Since libraries are specific to a particular target platform, you’ll need platform-specific instructions for each platform that uses the library.

  6. In your project’s youi folder create the folder cmake/Platform/.
  7. Create a new file based on the platform(s) you’re targeting. Call it one of YiAndroid.cmake, YiIos.cmake, YiLinux.cmake, YiWin64.cmake, YiOsx.cmake, YiPs4.cmake, YiTizenNacl.cmake, YiTvos.cmake, YiUwp.cmake, WebosCommon.cmake, YiWebos3.cmake, or YiWebos4.cmake.
  8. Put the following code in that file, updating the first line to correctly identify the file by the same name in You.i Platform and the target_include and target_link_libraries line to specify the location of header and library files.

        cmake_parse_arguments(_ARGS "" "PROJECT_TARGET" "" ${ARGN})
            message(FATAL_ERROR "'yi_configure_platform' requires the PROJECT_TARGET argument be set")
        _yi_configure_platform(PROJECT_TARGET ${_ARGS_PROJECT_TARGET})
        target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/thirdparty/hello/include)
        target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/thirdparty/hello/libHello.a)

All that’s left is to either wrap your library in a native module, or to initialize it in the App.cpp file. Which one you’ll use depends on whether or not the library exposes methods you want accessible from JSX. If you wrap it in a native module, be sure to include those source and header files in the SourceList.cmake file (as described above) and rebuild your application.

For example, consider a library called Hello that is specific to macOS (OSX). A simplified youi folder for including this library is as follows:


The header file for our example library, Hello.h is defined as:

#ifndef Hello_h
#define Hello_h

#include <string>

std::string getHello();


It’s likely anyone using this library would want to wrap getHello() in a native module to make it accessible from JSX. Since this library is specific to OSX, it’s important to only import it and use it when running on the OSX platform. It’s equally important to ensure that the code has an alternate path when run on another platform where the library isn’t available.

#include "myLibraryWrapperModule.h"

#include <youireact/NativeModuleRegistry.h>

#if defined(YI_OSX)
    #include <Hello.h>


#if defined(YI_OSX)
    return getHello();
    return "MyModuleWithLibrary no supported platform defined.";

Now, JSX files in this project can import NativeModules from react-native to access the name method from MyModuleWithLibrary.

const { MyModuleWithLibrary } = NativeModules;
export default class YiReactApp extends Component {
  render() {
    return (
      <View style={styles.mainContainer}>
        <View style={styles.bodyContainer}>
          <Text style={styles.headlineText}>{NativeModules.MyModuleWithLibrary.name}</Text>

Macro Reference

This section describes the macros you can use while creating your You.i React Native native module.

Macros for native module .h file

Macro Description
YI_RN_MODULE(MyModule) Identifies this class as a native module.
YI_RN_EXPORT_NAME(ModuleName) Exposes the native module name.
YI_RN_EXPORT_METHOD(Method) Exposes native module method to JavaScript.
YI_RN_EXPORT_CONSTANT(ConstantName) Exposes native module constant method to JavaScript.

Macros for native module .cpp file

Macro Description
YI_RN_INSTANTIATE_MODULE(MyModule) Instantiates your native module. Be sure to use the exact parameters as passed to the YI_RN_MODULE macro.
YI_RN_REGISTER_MODULE(MyModule); Registers the native module with You.i Platform.
YI_RN_DEFINE_EXPORT_METHOD(Class, Method) Implements an exposed method.
YI_RN_REGISTER_EXPORT_METHOD(Class, Method) Implements an exposed inline method
YI_RN_DEFINE_EXPORT_CONSTANT(Class, Constant) Implements an exposed constant method.
YI_RN_REGISTER_EXPORT_CONSTANT(Class, Constant) Implements an exposed inline constant method.