Complete Guide to Add Java or Kotlin Native Module inside React Native App

Complete Guide to Add Java or Kotlin Native Module inside React Native App

Post by: Niraj Dhungana

Posted on: Mar 2 2022

#react native# android studio# native module

After learning React Native I used to think I would be a master of native applications. I don’t need Java, Kotlin or Objective C. And if you also think so, then wake up my friend it’s time to learn new things. Because =>

There are five important things for living a successful and fulfilling life: never stop dreaming, never stop believing, never give up, never stop trying, and never stop learning. ― Roy Bennett

Yes it is right React Native is so capable when it comes to building native applications but down the line when your experience grows. You will try to add more complex features in your applications.

There will be a time when you get stuck for the tiniest little sprinkling you want to add inside your app. No libraries are available or if the library is there but it’s full of bugs. What will you do? The answer is Native Modules.

Yes we can use Native Modules inside our react native application to add the feature that we want.

List of things that we will cover.

  • Opening our project inside Android Studio
  • Creating our native module
  • Creating our native module package
  • Connecting our native code with react native bridge
  • Getting back result
  • Testing our code
  • Fixing an error - native module is null (imp)

Opening our project inside Android Studio

First we will open our project only the android part inside android studio. You can also use your current editor but Java and Kotlin are not like your regular JavaScript. So having an IDE will help you because it helps you to avoid errors.

If you are using windows system to build your react native app and you don’t know how to set up android studio for your react native project. Then you can watch this video.

Open project in android studio

Now you can go to file > open inside your android studio and navigate to the android folder inside your project. If you already have an existing project running.

open react naitve project inside android studio

Otherwise you can simply click on the open option and navigate to the android folder inside your project.

Creating our native module

After opening your project inside the android studio we have to create our module. From the left go to your project section app > java > com.projectname. Now we can right click on that folder and create a new Java or Kotlin class. Like here I want to work with a file system so I will name it FileSystemModule.

creating native module

Now inside this module we will create our class by extending ReactContextBaseJavaModule. After that the most important thing is to return the name inside the getName method.

Note: Don't Forget To Import All of The Classes From. You can use alt + enter.

1
2
3
4
5
6
7
8
9
public class FileSystemModule extends ReactContextBaseJavaModule {
    public FileSystemModule (@Nullable ReactApplicationContext reactContext) {
        super(reactContext);
    }
    @Override
    public String getName() {
        return "FileSystem";
    }
}

This is the name which we will use inside our react native code to import Native Modules from Java or Kotlin. This is also the file where we will write all of the code.

Creating our native module package

After creating our module we need to create our package file. Like before, create a new class with the name package at the end. Like below FileSystemPackage.

creating native package

Now you can copy and paste the code from below inside your new package class. But the main important thing here is line number 13. Here we can add the modules that we have created so far. So that we can use the power of native code inside our react native.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class FileSystemPackage 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 FileSystemModule(reactContext));

        return modules;
    }
}

Change the module name in the line number 13 with the module name that you have. If you have multiple modules you can repeat this same process to other modules. Like below.

1
2
3
4
...
    modules.add(new MyFirstModule(reactContext));
    modules.add(new MySecondModule(reactContext));
...

Connecting our native code with react native bridge

Now we have created our module and the package so let’s connect this to our React Native bridge. You need to now open MyApplication.java class and add your package.

Inside ReactNativeHost you will find the getPackages method. Inside this method we can add the packages that we want to expose from our native code.

Now you can add the line of code from below inside the getPackages method (line number 7).

1
2
3
4
5
6
7
8
9
10
11
12
public class MainApplication extends Application implements ReactApplication {
...
        @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 FileSystemPackage());
          return packages;
        }
...

So we have completed the first part with the process we followed from up above. Now we can import our package which we made here inside our java to inside our react native project like this.

1
2
3
import { NativeModules } from 'react-native';
...
const { FileSystem } = NativeModules;

Now if you try to use this code then the FileSystem (or the package name that you are using) will be undefined. Don’t worry we will fix it at the end of this post.

Getting back results

Ok, now let’s see how we can send back results from inside our native code to react native. Here we will be using callback but if you want to use promises like async and await you can follow this tutorial.

Now we can add all the logics that we want to use inside our module class. In my case I have to write my codes inside the FileSystemModule.java file.

Here I will create simple logic to read the file size in java. For that we can use File class from java.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FileSystemModule extends ReactContextBaseJavaModule {
     ...

    // Reading file size
    @ReactMethod
    public void getSize(String fileUrl, Callback cb) {
        try {
            File file = new File(fileUrl);
            int size = (int) Math.ceil(file.length());
            cb.invoke(null, size);
        } catch (Exception e) {
             cb.invoke(e, null);
        }
    }
}

Inside this example simply we are creating a method called getSize where we are accepting two parameters: uri of the file and the callback. To invoke the callback we need to use the .invoke method.

Then if there is any error I am passing it as the first argument inside our callback and null for size otherwise we are doing the opposite.

Testing our code

Now we have everything that we need. So, let’s try to use the native module that we just created inside our react native project. For that we can use the code that we discussed earlier.

1
2
3
4
5
6
7
8
9
10
11
12
13
import { NativeModules } from 'react-native';
...
const { FileSystem } = NativeModules;
const App = () => {
    const getFileSize = (uri) => {
        FileSystem.getSize(uri, (err, size) => {
            if(err) return console.log(err);
            
            console.log(size);
        })
    }
    return ...
}

Like we discussed earlier, if we try to use this code then most of the time we will get an error something like can not read getSize from null.

Fixing an error - native module is null

Now if you want to know more about this then I already have a post on this topic but the simple conclusion from that post is.

  • Kill the server where you are running your react native app.
  • Uninstall the app from your emulator or device.
  • Re-run your react native app.
  • If you are still getting that error, enable debug mode.

Not: To enable debug mode you can press d inside your terminal where you are running your server and select debug inside your emulator.

So, that's it for this post. Post written by @ndpniraj