Using Android emulator with Expo in Docker

1 minute read

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.

Android Emulator

Updated: