Expo is great for building apps that don’t require custom native code. But what if you need to integrate a native SDK? Or embed React Native into an existing native app? Or implement some highly performant custom native UI? Then, you will have to “eject” your Expo app and bring your native skills to the table.

This article aims to be a comprehensive guide to the tricks you need to know to unleash React Native’s full potential on the Android platform. It covers four scenarios:

Embedding React Native into an existing Android app Implementation of custom native components Invocation of native methods from the JavaScript side Triggering of JavaScript methods from the native side

For an example app which showcases all these scenarios, head over to the demo repository on GitHub. To discover the basics behind the implementation, read on, as we go through it case by case.

Note! If you are not familiar with how React Native works under the hood, I recommend you to first read “React Native: What it is and how it works.”

The demo app, available on GitHub

Scenario 1: Embed React Native into an existing app

The example app contains two Android activities. One fully native and one React Native activity. The native activity has a button that navigates to the React activity. Together, they demonstrate how you can integrate React Native into an existing app. Similar to what Facebook (code.facebook.com article) and Instagram (Medium article) do for their flagship apps.

Key steps

Important details

You’ll want to have a look at ReactActivity.java ’s onCreate method, where the React application is created and started.

Official documentation

React Native docs: Integration with Existing Apps

Scenario 2: Implement a custom native component

There are plenty of core React Native components. But sometimes, there is a need for a custom one. The React activity of the example app displays one such fully custom native component. It’s a simple square counter that gets incremented when touched. A React alert message is shown when the counter is incremented for the first time. Its purpose is to demonstrate how the native component’s events can be propagated to and handled from the JavaScript side.

Key steps

Optional steps

Override requestLayout in case the component’s bounds might change over time Allow propagation of native events to the JavaScript side by overriding getExportedCustomDirectEventTypeConstants in the view manager Emit events to the JavaScript side via reactContext.getJSModule(RCTEventEmitter.class).receiveEvent

Important details

Take a glance at CounterView.java 's constructor, where the XML layout is inflated. Also, check out CustomCounter.js , where the counter is imported and made available for usage.

Official documentation

React Native docs: Native UI Components

Note! The official documentation does not cover the end-to-end process. Instead, it walks us through the exposure of a subset of the existing ImageView available in the core library.

The example app. Left: native toast triggered from JavaScript. Right: React alert triggered from Java.

Scenario 3: Invoke a native method from JavaScript

To demonstrate how a native method can be invoked from JavaScript, the demo app contains a button that says “Show native toast from React.” When touched, it displays an Android toast message. The message is created and displayed entirely at the native side. The same communication mechanism is used for implementing bridges towards native libraries.

Key steps

Optional steps

Override getConstants to expose predefined values Wrap the native module in a JavaScript module to make access simpler

Important details

Read about the different argument types supported by @ReactMethod s. Also, find out how you can use async/await to get the result of a method.

Official documentation

React Native docs: Native Modules

Scenario 4: Trigger a JavaScript method from native

The example app’s React activity contains another button, “Trigger React alert from native.” The button triggers an emission of an event from the native to the JavaScript side. The emitted event is then handled and a React alert message is used to signal the success. This shows how you can initiate communication to the JavaScript from the native side.

Key steps

Emit an event to the JavaScript using reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit Use DeviceEventEmitter.addListener to listen for emitted events Don’t forget to remove the listener via DeviceEventEmitter.removeListener

Official documentation

React Native docs: Sending Events to JavaScript