Using Android emulator with Expo in Docker
Meet Kinksters’ mobile app is built with Expo, an opinionated set of defaults for React Native, paired with a simplified build pipeline for iOS and Android binaries. It’s great.
My preference, whenever I can, is to run software under development in a Docker container. This helps isolate dependencies, provides better dev-to-prod parity, and keeps my laptop a little “cleaner.”
Running Expo in Docker is easy enough:
docker-compose.yml
version: '3'
services:
expo:
image: node:14
working_dir: /build
volumes:
- ./app:/build
user: $USER_ID
command: node_modules/.bin/expo start
environment:
REACT_NATIVE_PACKAGER_HOSTNAME: docker-bridge.local
EXPO_DEVTOOLS_LISTEN_ADDRESS: 0.0.0.0
ports:
- 172.17.0.1:19002:19002
- "0.0.0.0:19000:19000"
This setup works “fine” if you’re using Expo Go on a physical device on the same LAN. But
what about emulation? Clicking the Run on Android device/emulator
button inside of the Expo Developer Tools UI
or running expo run:android
both attempt to call adb
, which isn’t present inside the container.
There are a few tutorials around the web that cover installing adb
along with node
, but this seemed excessive. A
static analysis of the code behind
expo run:android
led me to understand Expo simply starts a virtual device (emulator), installs Expo Go and then
points the app at Metro Bundler. So, why not just do that ourselves?
I followed the Expo documentation on installing Android Studio and the Android SDK, and creating an emulator. Ignore the part about saving the path to the SDK or adding it to your shell.
You’ll notice I set REACT_NATIVE_PACKAGER_HOSTNAME
to an arbitrary, non-publicly-routable hostname, but not
localhost
. I’m running Linux, so I know with confidence that the Docker
bridge interface address is 172.17.0.1
. I added this to my laptop’s
/etc/hosts
file.
/etc/hosts
172.24.0.1 docker-bridge docker-bridge.local
Since the emulator defers to my laptop for performing DNS lookups, this now allows my emulated Android device to connect to Expo. Now, I just need Expo Go installed. You could “just” use the IP, but I find this more semantic.
Download the APK from the Expo Go downloads page, start the virtual device and run
adb install [path-to-apk.apk]
.
Expo Go looks for an exp://
URL on the device clipboard to add a new project, but I couldn’t quite figure out how to
paste arbitrary text to the clipboard. Instead, I used the emulator testing UI to send the device an SMS containing
the URL. Copy the message contents and you’re done!
Expo Go will now hot-reload your application.