In this post, you'll learn what ExpoKit is and how it is used for adding native functionality to Expo apps. You'll also learn some of its pros and cons.
In my Easier React Native Development With Expo post, you learned about how Expo makes it easier for beginners to begin creating apps with React Native. You also learned that Expo allows developers to get up and running with developing React Native apps faster because there's no longer a need to set up Android Studio, Xcode, or other development tools.
But as you have also seen, Expo doesn't support all of the native features that an app might need. Though the Expo team is always working to support more native functionality, it's a good idea to learn how to convert an existing Expo project to a standard native project so you can easily transition if the need arises. So, in this two-part series, we'll take a look at how to do that.
In this post, you'll learn what ExpoKit is and when you're going to need it, as well as which of the Expo platform features are retained and lost once you detach to ExpoKit.
Prerequisites
This tutorial assumes that you've already set up your computer for Expo and React Native development. This means you will need either Android Studio or Xcode or both, depending on where you want to deploy. Be sure to check out the Get Started With Expo guide, and also the "Getting Started" guide in the React Native docs under the "Building Projects with Native Code" tab for your specific platform if you haven't done so already.
Knowledge of Node.js is helpful but not required.
What Is ExpoKit?
ExpoKit is an Objective-C and Java library that allows you to use the Expo platform within a standard React Native project. When I say "standard React Native project", I mean one that was created using the react-native init
command.
The downside of detaching to ExpoKit is that you will have to set up the standard native development environment for React Native!
Another downside is that you're limited to the React and React Native version used by ExpoKit at the time you detach your app. This means that there might be compatibility issues that you will need to resolve if the native module you're trying to install depends on an earlier version of React or React Native.
If you think your app is going to need a whole lot of native modules which the built-in React Native and Expo APIs don't already support, I suggest you avoid using the Expo APIs. That way, you can easily "eject" to a standard React Native project at the time you need to start using custom native modules.
When to Detach to ExpoKit?
You might want to detach your existing Expo project for any of the following reasons:
- The API exposed by native features supported by Expo doesn't cover your use case.
- You need to use a native functionality that's not currently supported by the Expo platform. Examples include Bluetooth and background tasks.
- You want to use specific services. Currently, Expo uses Firebase for real-time data and Sentry for error reporting. If you want to use an alternative service, your only option is to write your own code for communicating to the HTTP API about the services you want to use or to install an existing native module that does the job.
- You have an existing Continuous Integration setup which doesn't play well with Expo—for example, if you're using Fastlane or Bitrise for continuous integration. Expo doesn't really integrate with those services out of the box, so you'll have to write your own integration code if you want to use them while still on the Expo platform.
Features Retained When Detaching to ExpoKit
Detaching to ExpoKit means that you will lose some of the features offered by the Expo platform. However, the following essential features are still retained:
- Expo APIs. You'll still be able to use Expo APIs such as the Permissions API.
- Live Reload. Detached Expo apps are still able to use live reload while you're developing the app. The only difference is that you'll no longer be able to use the Expo client app. If you're developing for Android, you can still use your Android device or an emulator such as Genymotion to test the app. If you're developing for iOS, the app can be run on the simulators you installed in Xcode. You can also run it on your iPhone or iPad, but you need to follow some additional steps which I won't be covering in this tutorial.
Features You Lose When Detaching to ExpoKit
By detaching to ExpoKit, you will lose the following features:
- Easy app sharing by means of QR code and Expo Snack. Once you've detached to ExpoKit, you'll notice that you can still share your app via the Expo XDE. It will still generate a QR code, but that code will no longer work when you scan it with the Expo client app.
- Building standalone apps via Expo's servers. You can no longer use the
exp build
command to build the .ipa or .apk files on Expo's servers. This means that you have to install Android Studio or Xcode (depending on which platform you want to deploy) and build the app locally yourself. Alternatively, you can use Microsoft App Center to build the app if you don't have a local development environment set up yet. Note that you cannot use commands likereact-native run-android
orreact-native run-ios
to run the app, as you would in a standard React Native project. - Expo's Push Notifications service. Expo no longer manages your push certificates after detaching, so the push notification pipeline needs to be manually managed.
What We'll Be Creating
To showcase the benefit of detaching to ExpoKit, we'll be creating an app which needs a native feature that the Expo platform does not currently support. The app will be a location-sharing app. It will mostly run in the background, fetching the user's current location. It will then send that location via Pusher. We'll also create a web page showing the user's current location on a map.
Here's what the app will look like:
You can find the full source of the project in the tutorial GitHub repo.
Setting Up the App
In the remainder of this post, we'll focus on getting our app set up. Then, in the next post, we'll flesh out some of the key code to interact with ExpoKit.
Creating a Pusher App
If you want to use Pusher's services in your app, you'll need to create an app in the Pusher dashboard. Once logged in, go to your dashboard, click on Your apps and then Create new app, and enter the name of the app:
Once the app is created, go to App Settings and check the Enable client events check box. This will allow us to trigger Pusher events directly from the app instead of from a server. Then click on Update to save the changes:
You can find the keys under the App keys tab. We will be needing those later, once we connect to the Pusher app.
Creating a Google App
Similarly, we need to create a Google project in order to use the Google Maps API and the Geolocation API. Go to console.developers.google.com and create a new project:
Next, go to the project dashboard and click on Enable APIs and Services. Search for Google Maps JavaScript API and Google Maps Geocoding API and enable those.
From the project dashboard, go to Credentials and click on Create Credentials > API Key. Take note of the API key that it generates as we will be using it later.
Creating a New Expo Project
Run the following commands in your working directory:
exp init ocdmom cd ocdmom exp start
Now the Expo app is ready to test. Just scan the QR code with your Expo client app for iOS or Android.
Coding the App
Now we're ready to start coding the app. We'll start developing as a standard Expo project, and then we'll detach to ExpoKit when we need to use custom native features.
Generating the Unique Tracking Code
Clear the contents of the App.js file in the root of the project directory and add the following imports:
import React from 'react'; import { StyleSheet, Text, View } from 'react-native';
We'll also use a custom header component:
import Header from './components/Header';
In the constructor, set the unique_code
to its initial state:
export default class App extends React.Component { constructor(props) { super(props); this.state = { unique_code: Math.random().toString(36).substring(7).toUpperCase() // generate a random string }; } }
The UI of our app will display this unique code.
render() { return (<View style={styles.container}><Header text="OCDMom" /><View style={styles.body}><Text style={styles.input_label}>Unique Code</Text><Text style={styles.unique_code}>{this.state.unique_code}</Text></View></View> ); }
Finally, here's the code for the Header
(components/Header.js) component:
import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; export default class Header extends React.Component { render() { return ( <View style={styles.header}><Text style={styles.header_text}>{this.props.text}</Text></View> ); } } const styles = StyleSheet.create({ header: { flex: 1, flexDirection: 'column', alignSelf: 'stretch', paddingTop: 20, paddingBottom: 5, backgroundColor: '#f3f3f3' }, header_text: { fontWeight: 'bold', fontSize: 17, textAlign: 'center' } });
Conclusion
This has been the first part of our two-part series on detaching Expo apps to ExpoKit. In this post, you learned the concepts behind ExpoKit and began setting up a project that will use ExpoKit functionality.
In the next post, we'll detach the app to ExpoKit and then continue coding it so we can run it on a device.
In the meantime, check out some of our other posts about React Native app development!
- GraphQLCode an App With GraphQL, React Native, and AWS AppSync: The Back-End
- React NativeGet Started With React Native Layouts
- React NativePractical Animation Examples in React Native
- Mobile DevelopmentTools for React Native Development