Integration of React-Native Module into an existing Native App (Android)

Hello Friends, in this story you’ll be going to find out that “How we can integrate a new React-Native module/feature into an existing Native App only for android”.

Note: Integration into iOS app using Objective-C(In Progress)

As you know we can create a Hybrid Application from the Scratch in “React-Native”.

But what If you wanna create an independent module using React-Native and want to add it in your existing app, then a question arises that “Can I integrate independent React-Native module/feature with my native app? ”.

Then the answer is a BIG O(YES).

You only need to create a bridge between Native App & React-Native Module.

NOTE: It is assumed that you had already setup the environment for React-Native, Android & Created a React-Native Project. If not then please follow the instructions mentioned in the given link Setup & Create React-Native Project.

This can be done in following steps:
  1. React-Native Module/Feature/Component have to be developed before the integration.
  2. You’ve to add a ReactRootView class to your Android App. (This is a Container for your React-Native Module/Feature).
  3. Now you’re all set. Launch your ROCKET
Scenario:

1) Single Page Android App with One Button

2) On Click of that button React-Native Component will be open. The React-Native Component I’m going to use is StopWatch(GitHub Repo).


Step - 1: Create a new folder(I named it Bridge, this is our Project root Directory), inside that folder create an Android Project(Step-2) and Copy your React-Native Project(in my case StopWatch).
PROJECT STRUCTURE

StopWatch : Android Project

react-native-stopwatch-master : React-Native Component


Step - 2: Create a new Android Project, If you’re new then here is the Example. And add a Button in your Android App, Guide.

Step - 3: Update package.json inside your React-Native Project Root Directory(in my case react-native-stopwatch-master). And paste the following code in that file.
{
...
"dependencies": {
"minutes-seconds-milliseconds": "^1.0.3",
"react": "16.0.0-alpha.12",
"react-native": "0.47.0"
},
 ...
}

Step - 4: Install dependencies for React-Native (like react, react-native).

For this you’ve to run following command(Open Terminal and go to React-Native Project Root Directory):-

npm install

Note: This will create a node_modules folder, which is a backbone for your app development because it contains all the Javascript dependencies that you needed.


Step - 5: Configure Maven, Open Android Project and add React-Native Dependency to your app’s build.gradle(Module:app)
{
...
dependencies {
...
compile 'com.facebook.react:react-native:+' //Added Dependency
...
}
...
}

Note: You can replace “+” with your actual React-Native Version.


Step - 6: Now add an entry for local React-Native Maven directory to build.gradle (Project: Stopwatch{in my case})
Note: This is the path for Maven Directory of react-native library inside /node_modules of React-Native Project Root Directory.
{
...
allprojects {
repositories {
...
maven {
url "$rootDir/../<Project-Name>/node_modules/react-native/android"
}
}
}
...
}
Note: Replace “<Project-Name>” with your actual React-Native Project Folder name(in my case react-native-stopwatch-master).

Step - 7: Configure Permissions, now add following code inside the AndroidManifest.xml

***Manifest File in android provides essential information about your app to the Android system, which the system must have before it can run any of the app’s code.***

<uses-permission android:name="android.permission.INTERNET" />

Permission for Internet Access.

If you need to access to the DevSettingsActivity add to your AndroidManifest.xml:

<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />

Note: This is only really used in dev mode when reloading JavaScript from the development server.


Step - 8: Run your Android App, to check is everything fine.
If you found the following Warning, then ignore it
Error:Conflict with dependency 'com.google.code.findbugs:jsr305' in project ':app'. Resolved versions for app (3.0.0) and test app (2.0.1) differ. See http://g.co/androidstudio/app-test-app-conflict for details.

Step - 9: Now create an Empty Activity, guide to create activity.

Name that activity: ReactActivity, and paste the following code:

public class ReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
    private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//Container of your React-Native Module
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
mReactRootView.startReactApplication(mReactInstanceManager, "Stopwatch", null);

setContentView(mReactRootView);
}
    //Method to override BackPress Listener
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
    //Method to override onPause() method
@Override
protected void onPause() {
super.onPause();

if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause(this);
}
}
    //Method to override onResume() method
@Override
protected void onResume() {
super.onResume();

if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this);
}
}
    //Method to override onDestroy() method
@Override
protected void onDestroy() {
super.onDestroy();

if (mReactInstanceManager != null) {
mReactInstanceManager.onHostDestroy(this);
}
}
    //Method to override BackPress Listener
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
    //Method to Open DevMenu while App Development
    @Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}
}

Note: Import all classes, like

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;

Now, you’re all set with the ReactActivity Class.


Step - 10: It’s time to create a ROCKET_PROPELLANT that will take our ROCKET from the galaxy of Native Android App to galaxy of React-Native Module.

We’re going to add a event that will navigate the app from Native Screen to React-Native Screen.(If you’ve already Cooked it then ignore further steps)

In my case :

Open activity_main.xml, (inside app/res/layout in Android Studio) add the following code:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.via.cancel.stopwatch.MainActivity"
>

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Open Stopwatch"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</android.support.constraint.ConstraintLayout>
Open MainActivity.java and add the following code:
  1. You need to add Overlay Permission for development build, for this add the following code inside the onCreate() method
@Override
protected void onCreate(Bundle savedInstanceState) {
...
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
}
}
}

Note: Make a constant field OVERLAY_PERMISSION_REQ_CODE inside the class.

private static final int OVERLAY_PERMISSION_REQ_CODE = 1001;

2. And override the onActivityResult() to avoid the app crash condition:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
// SYSTEM_ALERT_WINDOW permission not granted...
Toast.makeText(getApplicationContext(), "Not Granted", Toast.LENGTH_LONG).show();
}
}
}
}

3. Now, it’s time to create an Event Listener for our Button “Open StopWatch”.

Add the following code inside the onCreate() method.

@Override
protected void onCreate(Bundle savedInstanceState) {
...
    Button clickButton = (Button) findViewById(R.id.button);
    clickButton.setOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
          Intent intent = new Intent(this, ReactActivity.class);
startActivity(intent);
}
});
}

Step - 11: Test your app.
  1. Open Terminal and go to your React-Native Project Directory and run the following command:
npm start

This will run the React Packager.

2. Run your app from the Android Studio.

Cool, you’re ready to launch your ROCKET.

<PRESS RUN BUTTON of ANDROID STUDIO>

Thanks for reading this article, please Share and 👏, if this article is helpful for you 🤓.