Running expo and raw react-native together

Hello world! Glad you asked this question, about ejecting your expo app. Well, you might have been asked by your senior developer, or boss or you might have just heard it from someone but don’t exactly have a good acquaintance with it. In this article we’ll try to answer these questions, all of you might be dead curious to know this in the simplest way –

  1. Why do we need to eject an expo app, although it gives us a tonne of features?
  2. Can we use some modules which have native code with expo like pusher, react-native-modal, etc?
  3. how to make expo and react native work together?

Let’s add a secret ingredient called expo-starter-kit to make all of this happen with a breeze.


Overview

Expo-starter-kit is a powerful, minimal configuration scaffolding tool, which provides a basic configuration for ejected apps built with expo, saving the developers from the hassle of manually ejecting apps. expo-starter-kit exposes an easy-to-use scripts’ list for handling builds, running an app in ejected as well as in unejected mode.



Features

Some of the features which make this module a boon for developers is-

  1. Minimal configuration
  2. Blazing fast development
  3. Rich script structure to run the app in ejected or unejected mode, with the help of just one command
  4. Do whatever you want in the Xcode and Android Studio projects
  5. Support for third-party native modules for React Native, non-Expo-specific instructions such as react-native link
  6. distribute your app as an ipa or apk without pain


Why should I eject my expo app?

And the answer is pretty simple. “Ejecting” is the process of setting up your own custom builds for your CRNA app. It can be necessary to do if you have needs that aren’t covered by CRNA or expo. Apps built with React-native are written in javascript, offering a bridge between writing old school platform-specific apps using kotlin, swift, etc. And this is the specialty offered by react-native, which makes it blazing fast and powerful to use.

However, there are some cases where advanced developers need native capabilities outside of what Expo offers out-of-the-box. The most common situation is when a project requires a specific Native Module which is not supported by React Native Core or the Expo SDK.

You might want to eject in the following cases:-

  1. If you do need to eject to build your own distribution package or to include your own native code
  2. If you wish to distribute your app to coworkers, friends, or customers. Right now you can do so by either making use of a service to host or build your CRNA app or by ejecting.
  3. If you wish to use a functionality that comes from interfacing directly with mobile platform APIs via Java, Objective-C, Swift, C, etc. As of right now, the only way to get direct access to these APIs from your app is by “ejecting” from CRNA and building the native code yourself.


Why is this module so special?

When building large, complex native apps using technologies like react-native or ionic, a programmer eventually feels the need for ejecting the application due to the reasons mentioned above and it is a universal truth that ejecting is a painful process.

Also, there might be some cases when a customer might force the programmer to use a native library, which expo or react-native might not offer out-of-the-box. These integrations require the use of react-native link which can only function in the ejected version of the app.

Therefore, this module is made as a headstart for running your app in ejected or unjected mode using simple, and easy to use commands.

Having said enough, let’s get into some real action-packed coding.


Getting Started

NOTE: The instructions below are written specifically for mac. Running Android version of windows should be pretty similar.

Setting up for an iOS device/simulator

Install the following module. Note it is npx (not npm)


npx create-expo-native-app

Install the dependencies.


npm install

Installation

Run the init script to specify your application name. It’s gonna prompt you for your app name and a slug name


npm run init

This package uses bundler as a dependency so let’s go ahead and install it through gem.


gem install bundler

Install the required native dependency files


npm run install-ios-libs

Cool! We’re good to go. Let’s run the app now. But make sure you have command 5 running in a separate terminal (depending upon whether you want to run the ejected or the unejected version).


react-native run-ios

BOOM, we’re up and running. Great job. Let’s come to the cool part. Try starting the app in ejected mode with this simple command

Did you notice that a small icon appeared at your ios simulator, rather than starting the app through expo? You’re right! You just successfully ran the ejected version of your app.


npm run ios-native

That’s not it, now try running the app in unejected mode.


npm run ios-expo



Setting up for an android device/simulator

Having things done for iOS device users, let’s make lie easier for android device users as well.

Follow steps 1 and 2, the same you did for iOS devices.

Installation

Run the init script to specify your application name. It’s gonna prompt you for your app name and a slug name


npm run init
This image has an empty alt attribute; its file name is Screen-Shot-2019-07-09-at-6.50.06-PM.png

Run this gradlew command in the android folder of your app (Make sure you have an AVD android simulator set up and running before running this command)


cd android && ./gradlew installDebug 

Open the android folder of your app in android studio, and hit the run button. This will sync and build the android version of your app.

Note:- Please install android studio v3.2.1 to avoid breaking errors.

Okay, fingers crossed! Let’s try running this in the ejected mode.


npm run android-native



5. Great job, let’s run it in the unejected mode as well.


npm run android-expo

Allow permit for drawing over other apps in the android device/ simulator and we’re good to go.

Phew! that was a long one. But fun isn’t it? Now you can go ahead and start building your app. Let’s move further.



How to add a native module into expo kit

Let’s start by building a mock file to mock a native module, which we might want to use other than the ones provided by the expo, and would have to eject our app in order to use it.

As an example, let’s try integrating “react-native-device-info“ into our app, which requires ejection from expo.


npm install react-native-device-info

And run the application in the unejected mode –


npm run ios-expo

And we’re greeted by this error… :/

Using the module in the unejected and ejected version of the app

No issues! Let’s try and fix this up.

Let’s start by creating a mock module file, mocks/DeviceInfoMock.js, to simulate the behavior of an external non-linked module –


export default class DeviceInfoMock {
    static getBrand() {
        return "expo dummy device"
    }
}

Next, set up your “babel.config.js“ file to set up an alias, so that it reads from the provided path –


const config = require('./config.json');
module.exports = function(api) {
  api.cache(true);
  const babelConfig = {
    presets: ['babel-preset-expo'],
    plugins: [
      [
        "module-resolver",
        {
          // "root": ["./assets"],
          alias: {

          },
          extensions: [".ios.js", ".android.js", ".js", ".json"],
        },

      ],
    ],
  };

  if(!config.isEjected) {
    babelConfig.plugins[0][1].alias['react-native-device-info$'] = './mocks/DeviceInfoMock';
  }
  return babelConfig
};

Let’s have a look at how have we used this module,


import React from 'react';
import {Video} from 'expo';
import {StyleSheet, Text, View, TouchableHighlight, Dimensions, TouchableOpacity} from 'react-native';
import {dismissModal, Modal, showModal} from 'expo-modal';
import DeviceInfo from 'react-native-device-info';

const {height, width} = Dimensions.get('window');

export default class App extends React.Component {

  render() {

    const innerComponent = <View style={{height: height/2 , width: width, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Hello world</Text>
      <TouchableOpacity onPress={() => dismissModal()} ><Text>close modal</Text></TouchableOpacity>
    </View>

    return (
        <View style={styles.container}>
          <Modal/>

          <Text>{DeviceInfo.getBrand()}</Text>
          <Video
              source={{uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4'}}
              shouldPlay={true}
              resizeMode="cover"
              style={styles.videoPlayer}
          />
          <TouchableHighlight
              onPress={() => {showModal(innerComponent)}}
          >
            <Text> Touch Here </Text>
          </TouchableHighlight>
        </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  videoPlayer: {
    position: 'relative',
    width: '100%',
    aspectRatio:3/2,
  },
});

So according to our logic, if the app is not ejected then the DeviceInfo must be fetched from our mock module instead of fetching it from react-native-device-info.

Now your screen must show ‘expo dummy device’ when starting the unejected version of your app –

CONGRATS! YOU JUST INTEGRATED A MODULE IN YOUR EXPO APP.

I hope you have noted the fact that for every native module, you have to write a mock for expo. But that’s pretty simple, just see the public functions of the module that you are using and return a mock data/behavior from there. And in your “babel.config.js“ file add the following line inside the if block


babelConfig.plugins[0][1].alias['react-native-device-info$'] = './mocks/DeviceInfoMock';

Closing thoughts

So, what we have accomplished with the above starter kit?

We have created a way in which we can run both expo and raw react-native codebase together.

And what did we achieve after doing so?

  • The devs who don’t need to work on the native modules will never need to touch the ios and android builds with this. They can simply keep on running expo even though the other dev is adding native modules.
  • The regular problem of developers building the app in expo, then ejecting it because of some use case, and then converting the expo coded UI in react-native is gone.

We are utilizing all that native modules have to offer without letting go of the development environment that expo offers.

Eager to contribute and improve the module, feel free to send us a PR here. https://github.com/codersera-repo/expo-native-starter-kit

Need some help in building your expo app? Feel free to get in touch with us here

Is react native open source?

React native is a framework for building native apps using React and JavaScript. … The best part is that its open-source; see the official React native repository on GitHub.

Is react a framework?

An Introduction to the  React framework. React(also known as React.js or ReactJs) is a powerful JavaScript library that uses server-side rendering (SSR) with a unique twist—one that allows it to provide a flexible, performance-oriented, componentized solution for the “V” in MVC (Model View Controller).

Is Expo good for react native?

Why it’s better to start your project with Vanilla React native. The biggest advantage of React native without  Expo is that you can link the packages that use native modules and connect your native modules written in native languages. You also have an opportunity to and implement for example a background geolocation.

Can we do react-native link using expo?

Yes you can do react-native link with expo but to do that you have use the starter kit mentioned in this project. You can do any native module changes and won’t lose anything provided by expo like push notification, over-the-air (OTA) updates provided by expo.

How to add native modules to expo?

Managed Expo projects don’t support custom native code, including third-party libraries which require custom native components. In a managed project, you only write JavaScript.
But if you do expo eject, you can add native modules but will lose other benefits provided by expo.
But there is a stater kit through which you can add native modules to expo and enjoy expo’s benefits as well which this article task about. https://github.com/codersera-repo/expo-native-starter-kit

0 thoughts on “Running expo and raw react-native together”

  1. Kostas Athanasiou

    Hello.

    Great post. However, I’m having trouble initializing my project.
    – Should I first eject my app and copy some of the files to the project I cloned from github?
    – You are using version 33 of the Expo SDK. Can I use a newer version?

    1. This is a starter kit. So, if you have already started a project in expo, transforming it into this starter kit would take quite a bit of effort.
      So, I would recommend you to start a project with this starter kit and copy paste all your files in this afterwards.

      This kit was built with expo 33, and should be compatible with version 34 as well. Although, we don’t recommend to use expo 34+.
      We’ll be updating this kit to newer version shortly.

      You can also watch this video and the next version for the setup help. https://codersera.com/blog/running-expo-react-native-together/

      hope this helps! Feel free to let us know if you face any issues setting up the project.

Leave a Comment

Your email address will not be published. Required fields are marked *