When developing with Expo, one of the challenges developers typically encounter is finding a compatible npm package. This is because the Expo package cannot add native modules - a huge obstacle for some projects. Yet, as there aren’t many pure-JS react-native packages around at the moment, the only way to continue your development would be to move the whole app back to a pure React-Native environment. Still, doing this can prove problematic if your code has already been built based on Expo specific features because you would have to remove a whole bunch of code and/or replace it with equivalent modules.
Luckily, Expo provides a way out of this sticky situation. A feature exists called Detach giving you what is essentially a simplified version of Expo client that you can tinker about with and build by yourself. Since you still have access to ExpoKit, everything else should still be running the same as before (with some exceptions, which we will discuss later).
If you’ve been enjoying the convenience of an Expo set up and you’ve never worked on a React-Native/mobile project before, the native client build process can seem terrifying. In particular because this approach can introduce a whole can of new bugs. Follow these simple steps for success:
Disclaimer: the assumption is you are developing for both Android/iOS
What do you need before detaching:
Exp-cli, which can be install using `npm install -g exp`
If you developed exclusively using Exp IDE before, then you may not have exp-cli installed.
A Macbook, or at least a computer with macOS.
Latest Xcode version
Latest Android Studio installation with Build Tools 26.0.1
Normally, Gradle will always make sure that you have all SDK-related packages installed, and you may have to restart Android Studio a few times, but it may fail to install this specific Build Tools, hence manual method is preferred.
A properly populated app.json (https://docs.expo.dev/distribution/building-standalone-apps/)
While you are at it, maybe it’s worthwhile preparing a proper icon and splash screen as well, so that the detaching process can help you bundle them with respective mobile clients. Otherwise, you need to do it manually later.
A backup push notification solution (if you’re using Expo Push Notification, as it doesn’t work with detached app)
Firebase Cloud Messaging / OneSignal can be a good candidate
Technically, you can detach the Expo app without Xcode/macOS but this approach is not recommended because it can render the detached iOS client crippled. It would be better to use a Mac, or at least one of the macOS Virtual Machines/Services available for the initial build.
What happens now?
Assuming you’ve prepared everything correctly, the whole detaching process should be quite seamless. After running `exp detach`, you will see two new folders named `ios` and `android` in your project root folder just like a normal React-Native application. By building the two native clients in those folders and deploying them to your phones, you should be set.
Warning: these 2 new folders should be committed and checked into your source control.
How do I develop from now on?
You will need to follow these steps so that an ExpoKit project can work properly:
Start the bundler using `exp start`
Build the native (ios/android) clients and deploy them to your phone.
Verify that your application is running as before.
Verify that your changes in JS code is served properly to your phone through the bundler.
The native clients on your phones will behave much like Exp client itself. What you need to be aware of is each time you add a new native module (described here: https://reactnative.dev/docs/linking-libraries-ios), you need to rebuild the native clients and deploy them to your phone again, otherwise your JS code will crash due to the absence of its native module counterpart.
Please be advised that even though your app is now technically a React-Native app, it’s still using ExpoKit, which means you still need to use Expo Bundler, as opposed to React-Native bundler. And standard React-Native-cli commands like `react-native start-ios` won’t work.
My push notification works but it opens to another instance of my app!
As we discussed before, Expo push notification won’t work with your app. In fact, you need to remove anything related to Expo push notification in your code and server-side code to avoid your backend code “accidentally” breaking the end-customer’s client. Any push notification send to new client with old Expo push token will render the app useless.
After you’re done with purging your code base, consider implementing a third party push notification solution like OneSignal or Firebase Cloud Messaging through a wrapping library such as react-native-fcm or react-native-onesignal. None of these libraries has the simplicity of Expo push notification, but they get quite close.
I get this error message “com.android.dex.DexException: Too many classes in --main-dex-list, main dex capacity exceeded” while building app for debug, how to fix it?
It is a known issue. For some reasons, Expo client for Android supports API level 19 for debugging. One way around it (for now) is to remove the dev19 flavor and use API level 21 as your testing baseline. It doesn’t happen for the actual release build with API level 19, so you can rest assured that your app will still support Android 4.4 devices.
More work around: https://github.com/expo/expo/issues/1166
“React/RCTEventEmitter.h file not found” or any of “file not found” message.
It is likely that the native modules you have added have dependencies on React, and was installed directly without using CocoaPod. There are a lot of issues when a non-Cocoa library has dependencies on Cocoa library, so the safest solution would be turning your non-Cocoa library to a CocoaPod one. Most React-Native native module packages should support CocoaPod.
Keep an eye out for my next blog post, in which I’ll reveal the best way to move from Expo/ExpoKit to a pure React-Native application.
Frequently Asked Questions about Expo and React Native
Can I switch from Expo to React Native?
Yes, you can switch from Expo to React Native, as Expo is built on top of React Native and uses the same underlying technology.
Can I use Expo packages in React Native?
In most cases, you can use Expo packages in a React Native project, although there may be some differences in how you use them depending on whether you're using Expo or pure React Native.
When integrating React Native into an established project, you can leverage the Expo SDK and development builds, but you'll still need to create a native development environment.
How is Expo different from React Native? Is Expo Better than React Native?
React Native CLI applications necessitate the use of macOS to construct iOS applications, which implies that Windows users must resort to questionable methods to develop iOS applications. Expo, on the other hand, offers a hosted service named EAS Build, which enables the building of app binaries for both Expo and React Native projects, thereby completely circumventing this restriction.
Despite being operated by an independent startup, Expo CLI is the preferred development environment recommended by the official React Native team. In fact, the React Native Community team advocates for developers to prioritize Expo CLI over their own React Native CLI by default.
Can we use both Expo and React Native CLI?
Yes, it is possible to use both Expo and React Native CLI together in the same project. Expo is built on top of React Native, so you can use any React Native component or API in an Expo project. However, if you need to use a module that is not available in Expo, you can eject your Expo project and continue with React Native CLI.
Is Expo good for React Native?
Expo facilitates the effortless building and deployment of React Native applications for both iOS and Android platforms. With Expo, there is no requirement to handle any native iOS or Android code, eliminating the need for developers to possess expertise in native mobile coding while constructing applications.
Does Expo compile to native code?
Expo Go does not allow you to add custom native code, you can only use native modules built into the Expo SDK. There are many great libraries available outside of the Expo SDK, and you may even want to build your own native library.