TL;DR - scroll to the end of the article for the main pros and cons of the 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 an MIT license. You can check them on a github. Sounds nice, doesn’t it? Of course, Expo XDE isn’t perfect, and using it sometimes can be challenging.
Expo XDE comes with certain limitations that developers should be aware of. For instance, it doesn't allow you to attach custom native code written in Java or Swift to your app. Expo apps also tend to be larger compared to their native counterparts, typically weighing in at a minimum of 20-30 MB. Additionally, if you require functionality that Expo XDE doesn't cover in its pre-built components, such as Bluetooth or background processing, you may find yourself unable to implement these features within the Expo environment. In such cases, the only recourse is to 'eject' the app from the Expo, which entails losing the advantages it offers, and continuing development outside of the Expo framework. Therefore, careful planning and consideration of your app's requirements are essential before opting to use this tool.
This article is based on the author's experience with two relatively small applications developed using Expo over 6 months in 2017 and 2018. While it may not provide an in-depth exploration, it does offer valuable insights worth sharing.
An example of an Expo React native app
Let’s see how the Expo works with this fast walkthrough. We will:
- Generate a new Expo app with Expo XDE
- Preview the app on a real device - with a live update
- Add a QR code scanner, using the Expo components library
- Add an independent npm package (Axios)
- Generate a stand-alone ‘.apk’ binary
- 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 a brief overview of the main features.
Up and running Expo project
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)- let's 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.
The main window of Expo XDE (Expo Development Environment)
After successful installation and running it, you should see a ‘welcome screen’ with a button to create a new app. Click it and let Expo XDE (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 run 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 a QR code with the address of the source JS bundle of your app. Based on this QR code, the mobile client will generate native packages, run them, and provide you with the full, native experience on your mobile device.
Expo scaffold app, with a slightly modified homepage
By default, Expo XDE propagates JavaScript files through Expo servers. So when you 'Share' and scan the QR code, your XDE sends JS files to Expo servers, and the mobile client downloads them from there. With this solution, anyone with a QR code can preview the code at the 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 (the source device with XDE and the client mobile device must be in the same WIFI network). You can use this option by clicking the 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, the 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 changing 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, the Expo mobile client provides a developer menu, which can be opened unusually - by shaking the device! After that, you should see the menu offering refresh, reload, disabling hot reload, and a few more options.
Contact us now to consult your mobile app project
More features from Expo XDE for your React native app
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 the LinksScreen.js file (in the ‘screens’ folder). It’s one of the sample screens generated by the tool. To get a sample implementation of the 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 the 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, the mobile app should automatically reload. On the ‘Links’ tab, you should see a 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’. The ‘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 compared to most popular external react-native packages, which in most cases do the same thing.
Adding an external ‘npm’ package to the Expo project
One of the most frequently asked questions about Expo is: "If Expo provides such a wide ecosystem, can I use my favorite npm packages along with it?” The answer is yes, in most cases. In the Expo project, you can add any npm packages that do not require the ‘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 the native code that Expo is based on. To add this kind of library to your React native app, you must ‘detach’ from the expo to gain full control of native modules. Unfortunately, you will also lose most of the key functionalities of the 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 a 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 to restart the project in XDE. Next, simply import the new package to the scanner file:
.. and replace the method for handling scanned QR codes with the following:
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 default values, but even with that, in our case, we had to provide an additional key value:
If all data is provided, you can start the generation procedure. Expo XDE 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”. The Expo app ships with many extra libraries to provide compatibility with many OS versions and Expo features, such as OTA updates. The app will also slightly reduce its size when uploaded to the proper store. Developers of Expo ensure that they keep working on reducing package size and providing a way to customize the number of attached libraries.
Testing OTA (over-the-air) updates in the React native Expo app
Over-the-air updates are a great feature that allows you to update the app on clients' devices, bypassing the App Store or Google Play. Let's see it in action.
We have already generated an '.apk' file that contains a unique identifier pointing to Expo servers. This is where the source JS files are stored. Let's change some text, for example, 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?
Why use Expo for your React native app?
Expo Pros:
- Significantly increased development speed and less friction early on
- You don’t need to write or configure any native code for 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
Expo Cons:
- If some aspect of device API is not covered, you can’t use it easily on your React native app
- Can’t attach custom native code
- You must install the Expo client app on the testers’ mobile device
- Final binaries are quite heavy (min 20-30 MB) thus downloading and uploading from your GitHub might take time
- Not every external node / react-native library will work with Expo apps
- Bugs freezes, looks and feel show that it’s not yet a fully mature solution
- It’s unclear how long the Expo will remain free and open-source
One final thing to consider is that Expo SDK is free FOR NOW. It’s possible that, if it becomes more popular, maybe developers will decide to claim some profits. Even if the source code for the previous versions is still under the open-source MIT license, some cloud solutions, such as push notifications or OTA updates, could become paid. This can be tough for some mobile app 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 in alternative to general react native development. 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.