This is Part 2 of React Native Bridge tutorial, focused on bridging Native classes to React. The tutorial can be found . Part 1 here In this tutorial, we will focus on creating cross-platform React Native which will work in Android and iOS. component both In of React Native Bridge, I started with iOS and then explained Android. This time I will start with Android and then explain ios. (Just to be natural 😉). But in the end, the same React UI component will work on iOS and Android. Part 1 The code of this article can be found here -> https://github.com/nalwayaabhishek/LightViewApp Create the LightApp To better understand Native Module we will create a simple LightViewApp example using react-native CLI. $ react-native init LightViewApp$ cd LightApp Next, we will create a component in Swift for iOS and Java for Android, and this will be used this app in a React component. This will be cross-platform example and the same React code will work in both iOS and Android. As we have created a basic skeleton of the project, next we have divided this article into two sections: Section 1 — Native Bridge UI component in Android Section 2 — Native Bridge UI component in iOS Section 1 — Native Bridge UI component in Android In this section, we will focus on Android and create a bridge between Swift/Objective C and your React Component. It has these three steps: Step 1) Create Bulb UI component Step 2) Passing props to component Step 3) Passing the Native state to React component Step 1) Create a Bulb View component To get started we will create a class in swift which will inherit from Android Button class. And then use this in our react code as component . BulbView <Bulb /> Open Android Studio and click on project and then select the folder inside our LightViewApp. Once all dependency is downloaded, create a Java Class as shown: Open an existing Android Studio android gradle BulbView.java Once the file is created, update the following code in : BulbView.java com.lightviewapp; package android.content.Context; android.graphics.Color; android.util.AttributeSet; android.view.View; android.widget.Button; import import import import import com.facebook.react.bridge.Arguments; com.facebook.react.bridge.ReactContext; import import BulbView Button { public class extends **public** BulbView(Context context) { **super**(context); **this**.setTextColor(Color.**_BLUE_**); **this**.setText(**"This button is created from JAVA code"**); } **public** BulbView(Context context, AttributeSet attrs) { **super**(context, attrs); } **public** BulbView(Context context, AttributeSet attrs, **int** defStyle) { **super**(context, attrs, defStyle); } } We have created a java class which is inherited from , and overwrite the constructor. We can customize Button color and button text. BulbView Button Next, we will create a BulbManager to expose and update the following code in BulbManager.java: com.lightviewapp; package com.facebook.react.uimanager.SimpleViewManager; com.facebook.react.uimanager.ThemedReactContext; import import BulbManager SimpleViewManager<BulbView> { public class extends @Override **public** String getName() { **return "Bulb"**; } @Override **protected** BulbView createViewInstance(ThemedReactContext reactContext) { **return new** BulbView(reactContext); } } We have inherited BulbManager class from . A SimpleViewManager is a React Native interface responsible for instantiating and updating views in the app. The SimpleViewManager is a generic class that uses our view. SimpleViewManager We always need a Custom Manager class which should be inherited from SimpleViewManager or its parent class ViewManager And in every Manager class, there should be always these two things: A method name getName, which return string name, which will be exposed to JavaScript Implement **createViewInstance(ThemedReactContext reactContext)**method in which we create an instance of the component and return the object. Manager class will be also used in the next section, where we will pass props from React Component. Next step is to register the module, if a module is not registered it will not be available from JavaScript. Create a file by clicking on Menu File -> New -> Java Class and the file name as and then click OK. And then add the following code to BulbPackage BulbPackage.java com.lightviewapp; com.facebook.react.ReactPackage; com.facebook.react.bridge.NativeModule; com.facebook.react.bridge.ReactApplicationContext; com.facebook.react.uimanager.ViewManager; java.util.ArrayList; java.util.Collections; java.util.List; BulbPackage ReactPackage {@Override List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { Collections. ();}@Override List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { Collections.<ViewManager> ( BulbManager());}} package import import import import import import import public class implements public return emptyList public return singletonList new We need to Override function and add the Bulb object to modules array. If this is not added here then it will not be available in JavaScript. createNativeModules package needs to be provided in the method of the file. This file exists under the android folder in your react-native application directory. Update the following code in BulbPackage getPackages MainApplication.java android/app/src/main/java/com/LightViewApp /MainApplication.java public class MainApplication extends Application implements ReactApplication {... @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>_asList_( new MainReactPackage(), ** new BulbPackage()** ); } ....} Now let’s update JavaScript code and access < from our React component. To do so open and update with the following code: Bulb> component App.js import React, {Component} from 'react';import {StyleSheet, Text, View, requireNativeComponent} from 'react-native'; const Bulb = requireNativeComponent("Bulb") export default class App extends Component { render() { return ( <View style={styles.container}> <View style={styles.top} /> ** <Bulb style={ styles.bottom } />** </View> );} } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#F5FCFF', }, top: { flex: 1, alignItems: "center", justifyContent: "center", }, bottom: { flex: 1, alignItems: "center", justifyContent: "center", }, }); Now run the react native app: Woo 💥 we can see <Bulb> has rendered a UI button which we have created in Java. The size and position of the button is decided from stylesheet which we have defined in React component. Step 2) Passing props to component In this section, we will extend component to accept props. We will add a props to Bulb UI component, which will change the color of the button, we created in the last section. Bulb isOn <Bulb style={ styles.bottom } isOn={true}/> First let's handle our button for accepting clicks using registers a callback to be invoked when we do some operation on Button and will be called when clicked a button. On clicking of button, we change the value of . Which then will change the color and text of the button. OnClickListener. OnClickListener onClick isOn Open BulbView and update the following code: package com.lightviewapp; import android.content.Context;import android.graphics.Color;import android.util.AttributeSet;import android.view.View;import android.widget.Button; import com.facebook.react.bridge.Arguments;import com.facebook.react.bridge.ReactContext;import com.facebook.react.bridge.WritableMap;import com.facebook.react.uimanager.events.RCTEventEmitter; public class BulbView extends Button { public Boolean = false;public void setIsOn (Boolean initialBulbStatus){ = initialBulbStatus;updateButton();} isOn isOn public BulbView(Context context) { super(context); **this.setTextColor(Color._BLUE_); this.setOnClickListener(changeStatusListener); updateButton();** } public BulbView(Context context, AttributeSet attrs) { super(context, attrs); } public BulbView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } **private OnClickListener changeStatusListener = new OnClickListener() { public void onClick(View v) { _isOn_ \= !_isOn_; updateButton(); } }; private void updateButton() { if (_isOn_) { setBackgroundColor(Color._YELLOW_); setText("Switch OFF"); } else { setBackgroundColor(Color._BLACK_); setText("Switch ON"); } }** } Next we will accept prop from JavaScript and assign the value of isOn to our class Bulb. Open BulbManager.java and add the following code: isOn BulbManager SimpleViewManager<BulbView> { public class extends .... @ReactProp(name= ) setBulbStatus(BulbView bulbView, Boolean isOn) {bulbView.setIsOn(isOn);} "isOn" public void ....} And then update the react code in : App.js <Bulb style={ styles.bottom } isOn={true}/> Now run the app in Android simulator: We can see the state of Bulb is passed to Android. You can try to change the value of and try to refresh the screen. isOn=false Passing the Native state to React component Now let’s add the Bulb Status(ON or OFF) value to our React screen. To do so we will add function to component and this will call when the button status is change. We will pass the function in component like this: _onStatusChange Bulb <Bulb style={ styles.bottom } isOn={this.state.isOn} onStatusChange={this._onStatusChange} /> Lets get started and update BulbView.js package com.lightviewapp;... import com.facebook.react.bridge.Arguments;import com.facebook.react.bridge.ReactContext;import com.facebook.react.bridge.WritableMap;import com.facebook.react.uimanager.events.RCTEventEmitter; public class BulbView extends Button {....private void changeStatus() {**WritableMap event = Arguments. ();event.putBoolean("isOn", );ReactContext reactContext = (ReactContext)getContext();reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(getId(),"statusChange",event);**if ( ) {setBackgroundColor(Color. );setText("Switch OFF");} else {setBackgroundColor(Color. );setText("Switch ON");} createMap isOn isOn YELLOW BLACK } ... } When a native event occurs the native code issue an event to the JavaScript representation of the View, and the two views are linked with the value returned from the method. getId() To map the s event name to the callback prop in JavaScript, register it by overriding the getExportedCustomBubblingEventTypeConstants method in your ViewManager. So lets update BulbManager.java tatusChange onStatusChange .... **import com.facebook.react.common.MapBuilder;import java.util.Map;** public class BulbManager extends SimpleViewManager<BulbView> {... **@Override public Map getExportedCustomBubblingEventTypeConstants() { return MapBuilder._builder_() .put( "statusChange", MapBuilder._of_( "phasedRegistrationNames", MapBuilder._of_("bubbled", "onStatusChange"))) .build(); }** } Finally let's create function in JavaScript, which will be called once the button is clicked. Update the React code in : _onStatusChange App.js import React, {Component} from 'react'; import {StyleSheet, Text, View, requireNativeComponent} from 'react-native'; const Bulb = requireNativeComponent("Bulb") export default class App extends Component { constructor(props) { super(props); this._onStatusChange = this._onStatusChange.bind(this); this.state = { isOn: false }; } _onStatusChange = e => { this.setState({ isOn: e.nativeEvent.isOn}); } render() { return ( <View style={styles.container}> <View style={styles.top} > <Text>This state of Bulb come from Native Code to JavaScript</Text> <Text>{this.state.isOn ? "Bulb is On" : "Bulb is Off"}</Text> </View> <Bulb style={ styles.bottom } isOn={this.state.isOn} onStatusChange={this._onStatusChange} /> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#F5FCFF', }, top: { flex: 1, alignItems: "center", justifyContent: "center", }, bottom: { flex: 1, alignItems: "center", justifyContent: "center", }, }); Now run the app in Android Simulator Woo we can see that in the top section the state of Bulb is reflected. Section 2 — Native Bridge UI component in iOS In this section, we will make the same Javascript code which we used for Android to work with iOS. This time we will create View class in Swift and expose the same implementation in Javascript. Bulb To get started we will create a BulbView class in swift, which will have a class variable and a few other functions. And then we will access this swift class from Javascript as a component. Let's start by opening file in ios folder. It should open Xcode with your ios code. isOn LightViewApp.xcodeproj Once you open the project in Xcode, then create a new Swift file as shown: BulbView.swift We have also clicked on Create Bridging Header which will create a file This will help to communicate between Swift and Objective C code. Remember that in a project we have only one Bridge Header file. So if we add new files, we can reuse this file. LightViewApp-Bridging-Header.h Update following code in file: LightViewApp-Bridging-Header.h #import "React/RCTBridgeModule.h" #import "React/RCTViewManager.h" #import "React/RCTEventEmitter.h" will provide an interface to register a bridge module. RCTBridgeModule Next, we will update with the following code: BulbView.swift UIKit import BulbView: UIView { class onStatusChange: RCTDirectEventBlock? @objc var isOn: Bool = { @objc var false { didSet button.setTitle(String(describing: isOn ? "Switch Off" : "Switch On"), for: .normal) button.backgroundColor = isOn ? .yellow : .black } } (frame: CGRect) { override init .init(frame: frame) super .addSubview(button) self } ?(coder aDecoder: NSCoder) { required init fatalError("init has not been implemented") } button: UIButton = { lazy var button = UIButton.init(type: UIButton.ButtonType.system) let button.titleLabel?.font = UIFont.systemFont(ofSize: 20) button.autoresizingMask = [.flexibleWidth, .flexibleHeight] button.addTarget( , self action: (changeBulbStatus), #selector for: .touchUpInside ) button return }() changeBulbStatus() { @objc func isOn = !isOn Bool as onStatusChange!(["isOn": isOn]) } } We have created a Bulb View which is inherited from . We have also created a variable which define the color and text of the button. Clicking on the button will call method. UIButton isOn changeBulbStatus Now create Bulb.swift as Swift file: And update the following code Foundation import @objc(Bulb) Bulb: RCTViewManager { class view() -> UIView! { override func BulbView() return } } We have created class which is inherited from RCTViewManager. The root class of most View class in React Native hierarchies is RCTViewManager, from which subclasses inherit a basic interface to the runtime system and the ability to behave as Objective-C objects. We can see that we have used @objc before a function and class, this will make that class, function or object available to Objective C Bulb The @objc attribute makes your Swift API available in Objective-C and the Objective-C runtime. Now create a new file from and select Objective-C file and then name the file as and update following code: File -> New -> File Bulb.m #import "React/RCTViewManager.h" RCT_EXTERN_MODULE(Bulb, RCTViewManager) @interface RCT_EXPORT_VIEW_PROPERTY(isOn, ) BOOL RCT_EXPORT_VIEW_PROPERTY(onStatusChange, RCTDirectEventBlock) @end React Native will not expose any function of Bulb to React JavaScript unless explicitly done. To do so we have used macro. So we have exposed Bulb class and to our Javascript code. Since Swift object is converted to Javascript object, there is a type of conversation. RCT_EXPORT_METHOD supports all standard JSON object types: RCT_EXPORT_METHOD() property NSString to string NSInteger, float, double, CGFloat, NSNumber to number BOOL to boolean NSArray to array NSDictionary to object with string keys and values of any type from this list RCTResponseSenderBlock to function Important Note: If you have skipped the Android part of this post, then you need to copy the React code in App.js. Now run the application in iOS Simulator: Now let’s fix the warning shown at the bottom of the simulator and in browser console: Module Bulb requires main queue setup since it overrides `init` but doesn’t implement `requiresMainQueueSetup`. In a future release React Native will default to initializing all native modules on a background thread unless explicitly opted-out of. To understand it better let’s understand about all the thread React Native runs: : where UIKit work Main thread where the layout happens Shadow queue: where your JS code is actually running JavaScript thread: Every native module has its own GCD Queue unless it specifies otherwise. Now since this Native module will run on a different thread and our main thread is depended on it, it’s showing this warning. And to make this code to run on MainQueue, open Bulb.swift and add this function. @objc static func requiresMainQueueSetup() -> Bool { return true } You can explicitly mention to run this in separate threat. return false Woo!! We have created a Native Bridge UI which is Cross Platform. If you want to read about Native Bridge out . Hope you find this useful. Please share your thoughts in comments. here If you liked the post, please share and give few claps👏