React Native Bridge For Android

React native bridge for android

Share This Post

Share on facebook
Share on linkedin
Share on twitter
Share on email

React Native is developed in such a way that we can create a bridge between the Native Language and the JavaScript code. A bridge is nothing but a way to setup communication between native platform and React Native.

But why do we need it?

Let’s assume you want to reuse some existing Java code or library without having to reimplement it in JavaScript. Yes, you guessed it right, you can use it in your React Native application with the help of Native Bridge. At some point of time, to make a production level application you will most probably need to use Native Bridge.

“As long as we are building our application purely within the framework, we can drive our app with properties and callbacks. But, when we mix React Native and native components, we need some specific, cross-language mechanisms that would allow us to pass information between them.”

What we will learn in this article?

We will separate this article in two parts which are:

  • Native Modules
  • Native UI Components

In this article, we are talking about android only.

Native Modules

A Native Module is just a set of javascript functions that are implemented natively for individual platform. Native Modules are used when React Native doesn’t have that required module yet, or when the native performance is significantly better.

To understand this concept better we will implement a toast mechanism in which the toast would be coming from the native android and we will call it from a button made in React Native. In case you are wondering “what a toast is?”, think of it as an alert message for your app.

Let’s start:

Before you start you should have Android Studio and Node.js installed in your computer.

Open your terminal and follow along

npx react-native init ReactNativeBridgeDemo

cd ReactNativeBridgeDemo

Where ReactNativeBridgeDemo is the folder name which will be created.

You will find a folder named ‘android’ in your project. Open that in Android Studio.

From there go to app> java > com.reactnativebridgedemo

There create two files with names ToastModule.java and MyPackage.java. You will understand in a bit that why we named that that way.

In ToastModule.java write the following code:

package com.reactnativebridgedemo;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import android.widget.Toast;

public class ToastModule extends ReactContextBaseJavaModule {
    //constructor
    public ToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }
    //Mandatory function getName that specifies the module name
    @Override
    public String getName() {
        return "ToastModule";
    }
    //Custom function that we are going to export to JS
    @ReactMethod
    public void showToast(String message) {
        Toast.makeText(getReactApplicationContext(), message, Toast.LENGTH_SHORT).show();
    }
}

We have created a ToastModule class which is inherited from ReactContextBaseJavaModule. ReactContextBaseJavaModule requires a function named getName whose purpose is to return the string name of the NativeModule which represents this class in the javascript.

@ReactMethod is used to expose a function in javascript as all functions are not exposed to JavaScript explicitly. These methods are of void return type.

ShowToast is the function we will be calling in react-native javascript code to create a native toast.

The next step in Java is to register the module, if a module is not registered it will not be available from JavaScript.

Now, in the MyPackage.java file, which we have created already, write the following code:

package com.reactnativebridgedemo;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class MyPackage implements ReactPackage  {
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
    
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        return Arrays.<NativeModule>asList(
                new ToastModule(reactContext)
        );
    }
}

We Override the createNativeModules function and added the ToastModule object to modules array. It needs to be added here to be available in javascript.

We are going to ignore the createViewManagers function for now as it will be covered in the UI Components part later in this article.

This MyPackage needs to be provided in the getPackages method of MainApplication.java file.

Now, open the MainApplication.java file and just add the following line in the getPackages function.

packages.add(new MyPackage());

just like, @Override

protected List<ReactPackage> getPackages() {
  @SuppressWarnings("UnnecessaryLocalVariable")
  List<ReactPackage> packages = new PackageList(this).getPackages();
  // Packages that cannot be autolinked yet can be added manually here, for example:
  // packages.add(new MyReactNativePackage());
  packages.add(new MyPackage());  //<---- ADD THIS LINE
  return packages;
}

Now, to access the showToast function we made in the ToastModule.java, we will make a button in react-native javascript which on clicking will invoke the showToast function.

This will be done by importing {NativeModule} from ‘react-native’ just like the following code in app.js.import React, {Component} from ‘react’;

import {Button, View} from 'react-native';
import {NativeModules} from 'react-native';
const {ToastModule} = NativeModules;
export default class App extends Component {
  _showToast() {
    ToastModule.showToast('This is a native toast!!');
  }
  render() {
    return (
      <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
        <Button onPress={this._showToast} title="Toast Btn" />
      </View>
    );
  }
}

This exposes the native ToastModule as a JS module.

On pressing the button the _showToast JS function will be invoked which will call the native showToast function in the ToastModule.js which will take a string which is nothing but the toast message.

Thats It.

Now, you can just start the application by the command:

npx react-native run-android

If it does not start the emulator for some reason, you can directly run it from the Android Studio by clicking the ‘run’ button in the toolbar.

You will be seeing the toast just like this,

The great thing is that we have created a Native Bridge for android. So, this was Native Modules, now let’s head over to the second part of this article which is Native UI Components.

Native UI Components

There are tons of native UI widgets out there ready to be used in the latest apps. Fortunately, we can wrap up these existing components for seamless integration with our React Native application. Without further ado, let’s head over to the practical part.

First, Let’s create a simple SwitchApp example using react-native CLI.

npx react-native init  SwitchApp

cd  SwitchApp

Now, Let’s create a Switch UI component. For that open this SwitchApp project in Android Studio just like we did in the Native Module section.

From there go to app> java > com.switchappand

There create three files with names Switch.java, SwitchManager.java and SwitchPackage.java. You will understand in a bit that why we named that that way.

Now, open the Switch.java file and write the following code:

package com.switchapp;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.widget.Button;
public class Switch extends Button {
    public Switch(Context context) {
        super(context);
        this.setTextColor(Color.BLUE);
        this.setText("This button is made in JAVA");
    }
    public Switch(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public Switch(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
}

Here we have created a Switch java class which is inherited from a Button, and the constructor is overwritten. Button text color and text is also customized.

Now, we need a SwitchManager to expose the Switch.java class. So, write the following code in SwitchManager.java:

package com.switchapp;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
public class SwitchManager extends SimpleViewManager<Switch> {
    @Override
    public String getName() {
        return "Switch";
    }
    @Override
    protected Switch createViewInstance(ThemedReactContext reactContext) {
        return new Switch(reactContext);
    }
}

Here, we have inherited SwitchManager class from SimpleViewManager. Native views are created and manipulated by extending ViewManager or more commonly SimpleViewManager. A SimpleViewManager is convenient in this case because it applies common properties such as background color, opacity, and flexbox layout.

We always need this custom Manager which should be inherited from ViewManager or SimpleViewManager.

Every Manager class, should have the following:

  • getName() method, which returns a string name, which we will use to call in javascript.
  • createViewInstance(ThemedReactContext reactContext) method in which we create an instance and return the object.

This SwitchManager will also be used in passing props from React Component.

Now, the next step in Java is to register the module, if a module is not registered it will not be available from JavaScript. This step is very much similar to the step we did in NativeModule section.

Now, in the SwitchPackage.java file, which we have created already, write the following code:

package com.switchapp;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.modules.toast.ToastModule;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SwitchPackage implements ReactPackage  {
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.<ViewManager>asList(
                new SwitchManager()
        );
    }
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

We Override the createViewManagers function and added the SwitchManager object to modules array. It needs to be added here to be available in javascript. That’s why we ignored  createViewManagers in the Native Modules section as it is for the UI components.

This SwitchPackage needs to be provided in the getPackages method of MainApplication.java file.

Now, open the MainApplication.java file and just add the following line in the getPackages function.

packages.add(new SwitchPackage());

just like,

@Override

protected List<ReactPackage> getPackages() {
  @SuppressWarnings("UnnecessaryLocalVariable")
  List<ReactPackage> packages = new PackageList(this).getPackages();
  // Packages that cannot be autolinked yet can be added manually here, for example:
  // packages.add(new MyReactNativePackage());
  packages.add(new SwitchPackage());  //<---- ADD THIS LINE
  return packages;
}

Now to use this UI button, we have just made in Java, in react-native javascript.

This will be done by importing {requireNativeComponent} from ‘react-native’ just like the following code in app.js.

import React, {Component} from ‘react’;

import {StyleSheet, View, requireNativeComponent} from 'react-native';
const Switch = requireNativeComponent('Switch');
export default class App extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Switch style={styles.javaBtn} />
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'pink',
    alignItems: 'center',
    justifyContent: 'center',
  },
  javaBtn: {
    height: 100,
    width: 300,
    backgroundColor: 'yellow',
  },
});

The requireNativeComponent function takes the name of the native view. In this case, we used the name “Switch” and now <Switch> component is ready to be used. Now we have a button which is made in Java and shown in the app through javascript.

You will be seeing the button just like this,

We have successfully rendered a UI button <Switch> which we made in Java.

Now, we will enhance this component to accept props from the javascript code, which we are going to use the change the color of the button deciding whether the switch is ON or OFF.

First, let’s pass a prop name isTurnedOn in the <Switch> component like:

<Switch style={styles.javaBtn} isTurnedOn={true} />

isTurnedOn will take boolean values which when true, the color of the button will be yellow and when false then the color  would be grey.

Now, open SwitchManager.java and add the following method in the SwitchManager class.

@ReactProp(name="isTurnedOn")
public void setSwitchStatus(Switch switchView, Boolean isTurnedOn) {
    switchView.setIsTurnedOn(isTurnedOn);
}

Properties that are to be reflected in JavaScript needs to be exposed as setter method annotated with @ReactProp (or @ReactPropGroup). Setter method should take view to be updated (of the current view type) as a first argument and property value as a second argument. In the above example, we are calling the setIsTurnedOn method with a boolean value as argument which we got as prop from the react-native javascript code. We will define this method in Switch.java.

Now open Switch.java and update the following code:

package com.switchapp;
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 Switch extends Button {

    public Boolean isTurnedOn = false;

    public void setIsTurnedOn (Boolean switchStatus){
        isTurnedOn = switchStatus;
        changeColor();
    }
    public Switch(Context context) {
        super(context);
        this.setTextColor(Color.BLUE);
        this.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                isTurnedOn = !isTurnedOn;
                changeColor();
            }
        });
        changeColor();
    }
    
    private void changeColor() {
        if (isTurnedOn) {
            setBackgroundColor(Color.YELLOW);
            setText("I am ON");
        } else {
            setBackgroundColor(Color.GRAY);
            setText("I am OFF");
        }
    }
    
    public Switch(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public Switch(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
}

Here we defined the setIsTurnedOn method and called the function changecolor to change the color and text of the switch button according to the prop which we provided in javascript. An onClickListener is also set up for changing the color and text of the button on clicking event.

That’s it!!

Now, try to run the app in the android emulator. You’ll see something like this:

And after clicking on the button:

You can try to change the value of the isTurnedOn prop in the javascript code and see the results for yourself.

In this article, we have created both the Native Modules and Native UI components and used them through the react-native javascript code.

Subscribe To Our Newsletter

Get updates and learn from the best

More To Explore

Want To Hire Top Remote Developers?

Drop Us A Quick Message