How to make friends React Native and Java code on Android

The need to work with the native part of a React Native application usually arises when a service does not have a special api for RN. Thus, a good developer should be able, at a minimum, to understand how the native part of the application works. This article will provide examples of how a React Native app interacts with Android.



Native module



First, let's create a new class in the android / app / src / main / java folder, the CustomModule class:



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

import java.util.Map;
import java.util.HashMap;

public class CustomModule extends ReactContextBaseJavaModule {
    CustomModule (ReactApplicationContext context) {
        super(context);
        reactContext = context;
    }

    @Override
    public String getName() {
        return "CustomModule";
    }

    private static ReactApplicationContext context;
}


This class contains the required getName () method. It is by the name that this method will return that you can access the native module from the Javascript code (more on that later).

Note also that the class constructor takes the application context as an argument. The application context is needed when we want to interact with Android components.



Let's create a method of the CustomModule class that will be called from the Javascript code:



@ReactMethod
    public void show(String message, int duration) {
        Toast.makeText(context,"Hello world", Toast.LENGTH_LONG).show();
    }


Note that in order for the method to be available in RN, you need to use the “@ReactMethod” decorator.



The Toast class is an Android component that can trigger the popup message from below using the show () method.



Linking the module with the Android application



After the module has been created, it must be placed in a package (“package”).



Let's create a package in the same namespace:



package com.awesomeproject;

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.ArrayList;

import java.util.Collections;
import java.util.List;

public class CustomPackage implements ReactPackage {

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new CustomModule(reactContext));
        return modules;
    }

}


The “ReactPackage” interface contains two required methods: “createNativeModules” and “createViewManagers”. View manager in RN code is a component. Our module will use functions and is not an Android ui component and therefore is placed in the “createNativeModules” method.



Note: one package can contain several modules.



Next, the package must be associated with the Android application as follows:



    //MainApplication.java

@Override
    protected List<ReactPackage> getPackages() {
      @SuppressWarnings("UnnecessaryLocalVariable")
      List<ReactPackage> packages = new PackageList(this).getPackages();
      packages.add(new CustomPackage());
      return packages;
    }


Using a module in Javascript code



Now let's try to call the “show ()” method in the RN application:



const App = () => {
  NativeModules.ToastExample.show();
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}>
          <Text>text</Text>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};


Result:







Data exchange between RN and Android apps



Now, let's exchange data between applications. Let's create two new methods in the CustomModule class to find the sum:



      @ReactMethod
    public void sum(int a, int b, Promise res) {
        try {
            res.resolve(a+b);
        } catch (IllegalViewOperationException e) {
            res.resolve(e);
        }
    }


@ReactMethod
    public void sum(float a, float b, Callback success, Callback fail) {
        try {
            success.invoke((a+b));
        } catch (IllegalViewOperationException e) {
            fail.invoke(e.getMessage());
        }
    }


The variables "a" and "b" will come from Javascript code and you need to remember about the correspondence of data types between Java and JS:







Note: since the Number type corresponds to several types from Java at once, we use an overload by creating two methods with the same name, but different types of parameters.



To return data to JS code, the com.facebook.react.bridge module contains the Promise and CallBack types.



Now let's use the method in Js:



const showRes = async () => {
const res = NativeModules.SendDataToRN.sum(400, 250);
   alert(res);
};

const App = () => {
   React.useEffect(() => {
	showRes();
   }, [])

  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}>
          <Text>text</Text>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};


Result:







Conclusion



The materials of the article can be used in all situations when the api for rn has not yet been written. As you can see from the examples, data exchange between applications is a fairly simple operation that does not require deep knowledge of Java programming.



All Articles