Thereâs a lot of great React Native modules out there, but most of them require a custom iOS or Android build, leaving âejectingâ as the only option for Expo users. That changed in SDK >42, when Expo added the ability for Expo Application Services to create custom development builds of your app.
Whatâs a custom development build? Itâs not just any Expo Go app, itâs your Expo Go app; complete with any React Native module you ever wanted, all without ever having to hit the eject button.
And now that Expo 43 includes React Native 0.63, Flipper by Facebook is available by default; thereâs no better time to ditch the old âChrome Developer Toolsâ way of debugging your React Native app. Not only will you gain access to device information and crash logs, youâll also have Flipperâs amazing plugin library. Everything from Apollo to Redux debuggers are in there.
If youâd like to skip to the end result, check out the jakobo/expo-cdc-example repo as thatâs what weâll be building towards.
Weâre going to start our journey by making a run-of-the-mill Expo application (install Expo CLI if needed with npm install -g expo-cli
). When we run expo init -t expo-cdc-example
, weâll be given a standard Expo application, configured for Typescript. If you would prefer vanilla JavaScript, just omit the -t
option. The result (minus our hidden folders and our lockfile) looks like this:
/
|- assets
|- app.json
|- App.tsx
|- babel.config.js
|- package.json
|- tsconfig.json
From here, we can run expo start
and view our Expo app. We could also build locally, but what weâre really looking for is to let someone else do all the work for us. This is doubly true if weâre developing on Windows, as XCode isnât even an option for making an iOS app. Enter Expo Application Services (EAS).
EAS lets you use Expoâs hardware to build your iOS/Android application, and has its own CLI. You can use EAS for building non-expo applications as well, so the EAS cli isnât bundled with Expo. Weâll need to install it globally like we did with our expo-cli
.
npm install -g eas-cli
Let that run, and youâll have a new eas
command available. The EAS CLI doesnât have an init
command, and while running the eas
build command will generate the configuration file for us, weâll have greater control if we create the file ourselves. Create a file named eas.json
in your application root and copy/paste the following configuration in:
{
"cli": {
"version": ">= 0.34.0"
},
"build": {
"base": {
"env": {}
},
"development": {
"extends": "base",
"developmentClient": true,
"distribution": "internal",
"releaseChannel": "default",
"android": {
"buildType": "apk"
}
},
"production": {
"extends": "base",
"distribution": "store",
"releaseChannel": "stable",
"android": {
"buildType": "app-bundle"
}
}
}
}
This sets up EAS to build something weâll call a âpreviewâ build. It will behave just like our production app, but itâs claimed ownership of the default release channel. By utilizing releaseChannel: "default"
in our development build, and not our production builds, we can make sure that an accidental expo publish
doesnât push code to our live application. Thereâs a lot more to eas.json
than weâre covering in this article, but the above is enough for us to launch our builds. If youâre already using the default channel for your app store releases, you can change value of the releaseChannel
property.
We can now tell EAS to build our app. Weâll want to specify our build profile preview as part of the command.
If this is your first time running EAS, youâll want to associate any iOS devices with your ad hoc provisioning profile. You can follow the steps in the Expo documentation, or just run eas device:create
and follow the prompts. To generate our build, we just need to run eas build --profile=preview
.
EAS will be off building things, and you can go get a cup of coffee. â
After a while, youâll have a shiny build that you can install on your iOS/Android device! EAS runs in the background too, so no need to wait for a build to finish, you can get back to coding.
So far, weâve created an Expo app, weâve configured EAS, and weâve kicked off a custom build. But EAS doesnât just let you make custom production builds, it lets you make development builds too! Thatâs right, it is your own Expo Go, with your own modules. And weâll be using EAS to build it.
Enabling a development builds means creating a new profile in our eas.json
. These additions should go alongside your preview build.
{
"build": {
// ...
"devclient": {
"extends": "base",
"releaseChannel": "default",
"distribution": "internal",
"developmentClient": true,
"android": {
"buildType": "apk"
},
"ios": {
"simulator": true
}
}
}
}
Our new profile, devclient
adds a few EAS options. The developmentClient
flag tells EAS that we want a custom build of the Expo development app, and the ios.simulator
field tells EAS not to create an iOS app, but a bundle thatâs designed for the iOS Simulator.
Now, kick off your new build and go get more coffee. â
eas build --profile=devclient
When that finishes up, youâll have a custom simulator build. When you install that on your simulator and launch it, it will look different than your usual Expo Go app.
The Expo Custom Development Client launch screen
Instead of the usual expo start command, it tells us our app needs to be started with the --dev-client
flag, so letâs do that. Stop your expo start if itâs running, and restart it with expo start --dev-client
.
The project will show up in your development build with a URL structure of exp+<project>://expo-development-client/âŚ
. The exp+<project>
protocol helps the native OS tell the difference between your custom Expo app and any others you might have on the simulator or device.
So long, Expo Go, hello Development Builds. đ
All of the above setup needs to be done exactly once, and the payoff is huge. Weâre going to get a better debugger for React Native, called Flipper, by Facebook. Go download the app, and weâll set up our development build to use this native module.
First, weâll need to install Flipper and its dependencies, which is a straightforward pair of command: expo install react-native-flipper react-devtools-core
for our expo related code and yarn install expo-community-flipper
for our build plugin weâll be using later.
Then, weâll need to tell our App to connect to Flipper in our App.tsx
file:
// App.tsx
import { connectToDevTools } from "react-devtools-core";
if (__DEV__) {
connectToDevTools({
host: "localhost",
port: 8097,
});
}
Since weâve added a new native module, weâll need to create a new development build that has our native iOS and Android code bundled in. Because Flipper also requires changes to our appâs Podfile
, weâre also going to make use of Expoâs Config Plugin system. Because we already installed the community Flipper plugin, itâs as easy as adding the plugin to our app.json
.
{
"expo": {
// ...
"plugins": ["expo-community-flipper"]
}
One last time (and one last â): eas build --profile=devclient
Install the new build on your simulator, open up the Flipper App and it just works đ¤Ż
You can repeat this for any Native Module you want, though Flipper is an excellent starting point since it lets you use react-native-reanimated
v2 with TurboModule support, frees you from the built-in Chrome debugging tools, gives you crash logs, and more. Just remember that youâll need to create a new development build when you add a new module, or make judicious use of try/catch blocks to ensure you donât throw an error.
This is just the start of what you can do with Expoâs development builds and Native Module support. Most Native Modules will work out of the box in a development build thanks to React Nativeâs autolinking, but if you do need custom changes to your Info.plist
or Manifest.xml
files (or even editing a Podfile
like we did today), Expo can take care of that too as part of the build process. These config plugins let you modify the plist and manifest without ejecting your app and are configured from within your app.json
.
If you still run into issues, thereâs an #EAS channel on the Expo discord and the Expo Forums have an entire section dedicated to EAS.
Tweets, mentions, and trackbacksShare your thoughts
As this gets discussed, comments will show up here. If the post is new, it may take a bit for your thoughts to get from one side of the internet to the other.
CodeDrift is the personal website of Rudolph Jakob Heuser