TL;DR - scroll to the end of the article for the main pros and cons of Expo.

The main focus of Expo is to walk you through writing React Native apps without even installing X-Code or Android Studio, all with a simplified setup. It gives you nice functionality for showing your app to selected users at every development stage with only a QR code scan. All these features are currently free, under MIT license. Sounds nice, doesn’t it? Of course, Expo isn’t perfect, and using it sometimes can be challenging.

Expo imposes some limitations. For example, you can’t attach custom native code to your app (written in Java or Swift). Expo apps weigh more than native counterparts (min. 20-30 MB). If you want to use something that Expo doesn’t cover in its components (e.g. bluetooth or background processing), you just can’t do it. The only solution at that point is to ‘eject’ the app from te Expo environment, losing all of its advantages, and go from there. This is why planning your app is important before you decide to use this tool.

The article is written based on my experience with two relatively small applications built with Expo over a period of 6 months in 2017 and 2018. It’s not deep-dive content. You can’t name yourself an expert after that short period of time, but for sure you can tell something worth sharing. Here goes.

An example

Let’s see how Expo works with this fast walkthrough. We will:

  1. Generate a new Expo app with Expo XDE
  2. Preview the app on a real device- with live update
  3. Add a QR code scanner, using Expo components library
  4. Add an independent npm package (axios)
  5. Generate a stand-alone ‘.apk’ binary
  6. Install the binary on a real device and test on-air updates

We will try our best to make things as simple as possible, to provide brief overview of the main features.

Up and running

First, we want to generate an Expo project, with all its dependencies. You can do this using their CLI or the Expo GUI app, called XDE (Expo Development Environment)- lets focus on the second solution. Go to https://docs.expo.io/versions/latest/introduction/installation.html and follow the instructions to configure the development environment.

Main window of XDE (Expo Development Environment)

After successful installation and running it, you should see ‘welcome screen’ with a button to create a new app. Click it and let Expo (with 2 or 3 mouse clicks) generate a scaffold app with working tab-based navigation. If everything goes well, you should see something like this (on MacOs):

XDE with running project

Now the app is running. To preview it on a real device, you must first install Expo mobile runtime platform - it’s available on AppStore or Google Play, under ‘Expo Client’.

Android client of Expo platform

On Android you have the possibility to scan QR code with the address of the source JS bundle of your app. Based on this QR code, mobile client will generate native packages, run them, and provide you with the full, native experience on your mobile device.

Expo scaffold app, with slightly modified homepage

By default, XDE propagate JavaScript files through Expo servers. So when you ‘Share’ and scan QR code, your XDE sends JS files to Expo servers, and the mobile client downloads them from there. With this solution, anyone with QR code can preview code at current development stage. It’s a great feature to share your progress with your client or project manager.

If you want to work locally, you can switch to sharing files through WLAN (source device with XDE and client mobile device must be in the same WIFI network). You can use this option by clicking gearwheel icon in your XDE and picking “Host/LAN”. Now, after clicking ‘Share’, XDE will generate a QR code pointing to your local machine, from where your mobile client can get all the files. After scanning the QR code, mobile client should fetch the files and run your app instantly.

If you can see the welcome page of a sample Expo project, you are ready to make some live changes. Try opening your project in the editor, and change some text. XDE will detect the changes, and automatically send the new files to the mobile client, which should reload your app. Sometimes it can be tricky, from time to time, for no apparent reason, the client stops reloading. In most cases, rebooting the project from the QR code, or restarting the mobile client app should solve the problem.

To refresh the JS bundle manually, Expo mobile client provides a developer menu, which can be opened in an unusual way - by shaking the device! After that, you should see the menu offering refresh, reload, disabling hot reload, and a few more options.

Adding a QR scanner from the Expo library

Let’s add a QR code scanner to test some of the components built into Expo. We will use LinksScreen.js file (in the ‘screens’ folder). It’s one of the sample screens generated by tool. To get sample implementation of Expo QR code scanner, go to https://docs.expo.io/versions/v29.0.0/sdk/bar-code-scanner. To make it simpler, we will just take all that sample code, and replace with it the whole content of LinkScreen.js file. The only change we need is to replace the name of the main component with ‘LinksScreen’, to keep the routing functionality. After saving the file, mobile app should automatically reload. On ‘Links’ tab you should see brand new scanner - you can test it on any QR code.

Of course, not every component is so easy to implement. With maps, for example, you need to provide Google API keys to generate standalone ‘.apk’. ‘FaceId’ component requires additional permissions information to be added to app.json. But even with this, adding built-in components is very easy, especially when comparing to most popular external react native packages, which in most cases do the same thing.

Adding an external ‘npm’ package

One of the most frequently asked questions about Expo is: ‘If Expo provides such a wide ecosystem, can I use my favourite npm packages along with it?” The answer is yes, in most cases. In Expo project you can add any npm packages that do not require ‘react native link’ command. Why? Because ‘react native link’ modifies native libraries to make the package functional, and as we said before, you can’t manipulate native code that Expo is based on. To add this kind of library, you must ‘detach’ from expo to gain full control of native modules. Unfortunately you will also lose most of the key functionalities of Expo, such as live sharing and OTA (over the air) updates. For now, let’s add a standard npm package (one which doesn’t use ‘react native link’). For that we will use axios- package for making HTTP calls.

Let’s pick a simple goal: we want to put custom data from sample API (e.g. “https://jsonplaceholder.typicode.com/posts/1”) in an alert after scanning any QR code.

To add axios to your project, simply go with “npm install axios” as you normally would. After adding new packages, you may need need to restart the project in XDE. Next, simply import new package to the scanner file:

 
import axios from 'axios';

.. and replace the method for handling scanned QR code with the following:

handleBarCodeScanned = ({ type, data }) => {
   axios.get('https://jsonplaceholder.typicode.com/todos/1')
   .then(function (response) {
       alert(`scanned data: ${JSON.stringify(response.data)}`);
   })
}

Now, after scanning a QR code, an alert should be displayed with a todo object from jsonplaceholder. That’s all. No further configuration is required.

Generating ‘.apk’ file

Generation of ‘.apk’ file is possible through Expo CLI. Use “npm install -g expo-cli” to install the command line interface, then simply enter: “expo build:android”. Building ‘.apk’ requires adding configuration in app.json, such as name, bundle identifier and icon. Fortunately, Expo sets up many defaults values, but even with that, in our case we had to provide an additional key value:

"android": {
 "package": "com.samplecompany.sampleappname"
}

If all data is provided, you can start the generation procedure. Expo will ask you some questions about the build, but it also lets you use the defaults.

Generating APK takes place on Expo servers. After a while you will be provided with a status link. Once the process is complete, you can also download your app from the same place.

You may be scared by the size of the .apk file and the installed application. As explained in the official documentation : ‘If you need to keep your app size extremely lean, Expo may not be the best choice”. Expo app ships with many extra libraries to provide compatibility with many OS versions and Expo features, such as OTA updates. App will also slightly reduce its size when uploaded to proper store. Developers of Expo ensure that they keep working on reducing packages size, and to provide way to customise the amount of attached libraries.

Testing OTA (over-the-air) updates

Over-the-air updates are a great feature which lets you update the app on clients’ devices, bypassing the AppStore or Google Play. Let’s see it in action.

We have already generated an ‘.apk’ file which contains a unique identifier pointing to Expo servers. This is where the source JS files are stored. Let’s change some text, e.g. from ‘Get started by opening’ to ‘Welcome to Expo app’ in HomeScreen.js. Now click ‘Publish’ in XDE. This will send and replace the old versions of JS on the server. Every installed instance of the app, on every restart, will check if a new version is published and try to download it.

After publishing, try to restart the application you installed from the ‘.apk’ file. You should see an updated welcome page. How cool is that?

Ending word

One final thing to consider is that Expo is free FOR NOW. It’s possible that, if it becomes more popular, the developers will decide to claim some profits. Even if source code for the previous versions is still under the MIT license, some cloud solutions, such as push notifications or OTA updates, could become paid. This can be tough for some projects. In this case it seems like the only solution, other than going with the likely paid plan, would be to ‘eject’ from Expo or rewrite the whole app from scratch.

Even if it’s clear that Expo has a few weaknesses and it’s not suitable for every project, generally it’s a very useful tool. If you decide to fully integrate your new app with Expo and live with it for a while, I’m sure that you will at least consider using it once again in any further React Native project.

Pros:

  • Significantly increased development speed and less friction early on
  • You don’t need to write or configure any native code for a fully functional, production-ready code
  • Production, ‘on the fly’ updates, bypassing the app stores
  • Great sharing functionality for easy installation during development
  • Very rich, unified functions / components library (AR, Google and Facebook integration, Date/Time pickers, etc.)
  • Simplified generation of binary packages
  • You can move out of Expo by ‘ejecting’ at any moment
  • Nice multi-platform GUI client
  • MIT license

Cons:

  • If some aspect of device API is not covered, you can’t use it
  • Can’t attach custom native code
  • You must install Expo client app on testers’ mobile device
  • Final binaries are quite heavy (min 20-30 MB)
  • Not every external node/react-native library will work with Expo apps
  • Bugs, freezes, look and feel shows that it’s not yet a fully mature solution
  • It’s unclear how long Expo will remain free