It’s difficult to find clear, up-to-date instructions for writing a native Android module for your React Native project.
I spent about half a day piecing this all together from a few sources, so here’s how it ended up.
Prerequisites:
- React Native is installed and up and running
- If you used expo, you should have ejected already, and already got the packager up and running again (it’s a little bit of a battle)
- Android Studio is handy for pointing out syntax errors and code highlighting for .java files.
What will we achieve?
By the end of this article, you’ll have a module written in java that runs native code on your android device and returns the result to your javascript/React Native environment.
You’ll have:
- A module, which holds the Java class that runs your native functionality.
- A package, which connects (through code) your module to your React Native code.
- A javascript connector that you can call easily from your React Native code.
Preparing the module file
Pick a name for your module. This article uses “MyTestModule” for a module name and com.tester.tester_nativemodules for a package name.
Using the above, create a subfolder for your project files under
<project root>/android/app/src/main/java/com/<projectname>/tester_nativemodules/
Create MyTestModule.java inside that folder, and paste the following code.
Note where I’ve bolded the package name, and the module name is italic.
package com.tester.tester_nativemodules;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.NativeModule;
import java.util.Map;
import java.util.HashMap;
public class MyTestModule extends ReactContextBaseJavaModule {
public MyTestModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "MyTestModule"; /* Must match class name above! */
}
// Available as NativeModules.MyTestModule.processString
@ReactMethod
public void processString(String personName, Callback callback) {
callback.invoke("Hi there: " + personName);
}
}
The function in blue is the actual code that will be available from ReactNative. You can make as many of these as you need.
@ReactMethod makes this function available over in React Native land.
You can use any primitive types you need in the method signature, and you can add as many of these methods as you need. Above, we accept a “personName” string and a callback. We’ll pass our function output to callback so it can make it’s way back to React Native land.
Creating the package
The package is a file that exists just to bridge our module with React Native. It’s pretty generic, just make sure to set your package name and module name correctly. I’ve bolded/italicised them again below.
This file is “MyTestPackage.java”, and lives alongside MyTestModule.java in <project root>/android/app/src/main/java/com/<projectname>/tester_nativemodules/
package com.tester.tester_nativemodules; 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 MyTestPackage implements ReactPackage { @Override public List createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); } @Override public List createNativeModules( ReactApplicationContext reactContext) { List modules = new ArrayList<>(); modules.add(new MyTestModule(reactContext)); return modules; } }
Link it to the Android Packages list
The last step on java side is telling the android project your package exists. Open up <project root>/android/app/src/main/java/com/<projectname>/MainApplication.java and add your package name to the list of available packages. It should look something like this:
protected List getPackages() { return Arrays.asList( new MainReactPackage(), new SvgPackage(), new MyTestPackage() /* The name of your package class above */ ); }
Using the package in javascript
The new package is available at NativeModules.MyTestModule
.
Add an import at the top of your JS file,
import {NativeModules} from 'react-native';
and then you can call the processString function inside your JS file like this:
NativeModules.MyTestModule.processString("Rhys", function (response) { console.log(response); //Will log out "Hi there: Rhys" })
All done
That’s all there is to adding native code to a React Native project. Adding something trivial like above ensures you have all the nuts and bolts in place before adding more complicated functionality.