Home

React Native: Android Native Modules

Did you know that you can use native code in React Native? Yes, you can. Java or Kotlin for Android platform, and Swift or Objective C for iOS. We'll talk about Native Modules, what they can be used for, and create a simple Native Module for Android.

cover image

Intro

There will be a time when you will need access to a native platform API that is not available in JavaScript. This is where NativeModules come into play, a really powerful feature of React Native. You can write some high-performance code for things like image processing.

NativeModules expose instances of Java/Kotlin/Objective-C/Swift classes to JavaScript as an object. Basically, it all comes to this. You write a function with native language for the specific platform, you expose that function to JavaScript, and call it from wherever you want in React.

The only thing required for this is that you know the native language of the platform.

Setup

React Native docs have an example for NativeModules, but I find it confusing for beginners, as they are making a module to communicate with the phone's calendar to create events from your app.

In this post, we will focus on something simple and easy. We will return the current date and time from Java to JavaScript to show you how to implement NativeModules in your project, and then you can use that to continue writing NativeModule.

Creating NativeModule

First, we need to create a new directory in the project.

Go to android/app/src/main/java/com/your-project-name/ and create a directory called date. This is where our module will live.

Every module needs to have 2 files. DateModule.java and DatePackage.java. Always name these files like you named your directory (e.g. StringModule.java, StringPackage.java).

In DateModule.java we define our NativeModule, and we write code for it in that file. in DatePackage.java, we register our NativeModule and add it to ReactPackage to be used from within React Native code.

The code

Copy the following in the DateModule.java

package com.your-app-name.date; // replace com.your-app-name with your app’s name (can be found in android/app/src/main/AndroidManifest.xml) import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import android.util.Log; public class DateModule extends ReactContextBaseJavaModule { public DateModule(ReactApplicationContext context) { super(context); } }

This is boilerplate code, and here we just tell our DateModule to extend ReactContextBaseJavaModule, as it will give our module the ability to be recognized by React Native, and its lifecycle methods.

Module name

All Java native modules in Android need to implement the getName() method. This method returns a string, which represents the name of the native module

// add to DateModule.java @Override public String getName() { return "Date"; }

Export a Native Method to JavaScript

To get the current date and time in Java we need to import a class for that.

Add this at the top of DateModule.java

import java.time.format.DateTimeFormatter; import java.time.LocalDateTime;

And now we create our function that will get the current date, format it, and then send it when it gets called from JavaScript.

// add to DateModule.java @ReactMethod public void getCurrentDate(Callback cb) { try { DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd - HH:mm:ss"); LocalDateTime now = LocalDateTime.now(); cb.invoke(null, dtf.format(now)); } catch (Exception e1) { Log.d("DEBUG", "ERROR: " + e1.toString()); } }

DateModule.java looks like this

package com.your-project-name.date; // replace com.your-app-name with your app’s name (can be found in android/app/src/main/AndroidManifest.xml) import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import java.time.format.DateTimeFormatter; import java.time.LocalDateTime; import android.util.Log; public class DateModule extends ReactContextBaseJavaModule { public DateModule(ReactApplicationContext context) { super(context); } @Override public String getName() { return "Date"; } @ReactMethod public void getCurrentDate(Callback cb) { try { DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd - HH:mm:ss"); LocalDateTime now = LocalDateTime.now(); cb.invoke(null, dtf.format(now)); } catch (Exception e1) { Log.d("DEBUG", "ERROR: " + e1.toString()); } } }

Register the Module

After writing a native module, it must be registered with React Native. To do so, create a ReactPackage with your native module and register the ReactPackage with React Native. During initialization, React Native will loop through all packages and register each native module within each ReactPackage.

Add the following code to the android/app/src/main/java/com/your-project-name/date/DatePackage.java

package com.your-project-name.date; // replace com.your-app-name with your app’s name (can be found in android/app/src/main/AndroidManifest.xml) 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 DatePackage 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 DateModule(reactContext)); return modules; } }

After this, all that's left to do is importing DatePackage into the android/app/src/main/java/com/your-project-name/MainApplication.java.

First import DatePackage at the top of the file

import com.your-project-name.date.DatePackage;

Then locate ReactNativeHost’s getPackages() method and add your package to the packages list getPackages()

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 DatePackage()); //add this return packages; }

Testing what you've built

To import the newly created module in the ReactNative app we will use NativeModules from react-native like this

import { NativeModules } from 'react-native'; const Component = () => { const { Date } = NativeModules; Date.getCurrentDate((error, result) => console.log(result)); }

This will return the DateTime string if everything is working correctly. If not you can console.log(error) to see what went wrong.

Here is a sample code for creating a timer using this module.

App.js

import React, { useEffect, useState } from 'react'; import { View, Text, NativeModules, StyleSheet } from 'react-native'; const App = () => { const [date, setDate] = useState(''); const { Date } = NativeModules; useEffect(() => { setInterval(() => { Date.getCurrentDate((error, result) => setDate(result)); }, 1000); }, [Date]); return ( <View style={style.page}> <Text style={style.text}>{date}</Text> </View> ); }; const style = StyleSheet.create({ page: { flex: 1, alignItems: 'center', justifyContent: 'center', }, text: { fontSize: 22, }, }); export default App;

Conclusion

Native Modules are a really powerful feature in React Native because you can go outside of React Native's scope and write your own logic, function, and code that isn't supported by default.

I used Native Modules in my latest project to write a function for detecting VPN. What are you going to use it for?