Creating Native Modules in React Native using Java
Tags: reactnative, react, java, android
Published: 2020-09-19 12:25:05

In React Native, Native Modules are piece of code written in Java/Swift/ObjectiveC which is used to access the platform specific features like Accessing camera, bluetooth and other native APIs from the JavaScript code.

### When to create Native Modules?
1. When we try to access native features that doesn't exists in React Native modules.
2. Planning to reuse an existing java/swift library code in your React Native project.
3. Writing a multi-threaded code.
4. For time-taking tasks like DB Hit, Image processing, Encryption and other expensive operations which leads to JavaScript memory leaks.

### For instance, Take the use-case of encryption/decryption:

Typically, everyone will go for finding some JavaScript encryption library and add it into their React Native project. Here, the encryption/decryption will happen in the JS layer. It looks more performant when encrypting short texts. While encrypting large texts the encryption library might takes more time to process, which tends to block the UI thread and performance issue.

By creating custom Native Modules we can solve the above problem. The encryption logic should be moved to Native Layer from JS layer. Still, we can use the same java version of encryption library.

### Steps to create custom Native Modules (for the above encryption use-case):
**For android using Java:** <br>
1\. Create a new Java file named `EncryptionModule.java` inside the `android/app/src/main/java/com/your-app-name` folder and add the below content. <br>
```java
package com.your-app-name;

import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

public class EncryptionModule extends ReactContextBaseJavaModule {
    @Override
    public String getName() {
        return "Encryptor";  // Name of the Native Modules.
    }
}
```
2\. Add `encryption` method to `EncryptionModule`.
```java
/**
* @param plainText Text to be encrypted(from JS layer)
*/
@ReactMethod
public void encrypt(String plainText, Promise promise) {
    try {
      // Add your encryption logic here 
      // (can use any JAVA encryption library or use default)
      String encryptedText = plainText + "This is encrypted text";
      promise.resolve(encryptedText); // return encryptedText
    } catch (Exception e) {
      promise.reject("ENCRYPTION_FAILED", "Encryption Failed");
    }
}
```
3\. Add `decryption` method to `EncryptionModule`.
```java
/**
* @param encryptedText Text to be decrypted(from JS layer)
*/
@ReactMethod
public void decrypt(String encryptedText, Promise promise) {
    try {
      // Add your decryption logic here 
      // (can use any JAVA decryption library or use default)
      String decryptedText = encryptedText + "This is decrypted text";
      promise.resolve(decryptedText); // return decryptedText
    } catch (Exception e) {
      promise.reject("DECRYPTION_FAILED", "Decryption Failed");
    }
}
```    
4\. Register the above module: <br> Create a new Java file named `EncryptionPackage.java` inside the `android/app/src/main/java/com/your-app-name` folder and add the below content.
```java
package com.your-app-name;

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 EncryptionPackage implements ReactPackage {

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

@Override
public List<NativeModule> createNativeModules(
      ReactApplicationContext reactContext
) {
    List<NativeModule> modules = new ArrayList<>();
    // Register the encryption module
    modules.add(new EncryptionModule());
    return modules;
  }
}
```
5\. Add the above package into `MainApplication.Java` (`android/app/src/main/java/com/your-app-name/MainApplication.Java`).
```java
...
import com.your-app-name.EncryptionPackage;
...

protected List<ReactPackage> getPackages() {
  @SuppressWarnings("UnnecessaryLocalVariable")
  List<ReactPackage> packages = new PackageList(this).getPackages();
  // Add the encryption package here
  packages.add(new EncryptionPackage()); 
  return packages;
}
```
6\. Create a custom JS wrapper to access the Native Modules:<br> Create a new JS file named `Encryptor.js` under your project root directory.
```js
import {NativeModules} from 'react-native';

const Encryptor = NativeModules.Encryptor;

export const encrypt = (plainText) => {
  // Add your additional custom logic here
  return Encryptor.encrypt(plainText);
};

export const decrypt = (encrptedText) => {
  // Add your additional custom logic here
  return Encryptor.decrypt(encrptedText);
};
// You can directly export this and access it 
// like Encryptor.enrypt/Encryptor.decrypt
export default Encryptor; 
```
7\. Finally access `Encryptor` from any JS files like below.
```js
import {encrypt, decrypt} from './Encryptor';

const encryptText = await encrypt('some text');

const decryptText = await decrypt('encrypted text');
```

### Conclusion
Let's start creating Native Modules for time-taking operations or accessing native specific APIs.