Building standalone expo app locally with Turtle CLI | /var/log/share

Building standalone expo app locally with Turtle CLI

This should be a short post. One thing I struggled with when building Drone Trails on Android using expo is testing firebase login functionality. Expo provides two ways to do this - one is using google sign in web and the other one is the native experience. Here is the official link suggesting it can only be used in standalone apps. If you are like me and love testing on the expo client itself, it’s a pain when you want to test firebase login. You need to build and upload to expo every single time you want to test your apk.

Around a few days back, I found out you can install turtle locally. The same build tools that expo utilizes. Let’s go through step-by-step process to do this.

Step 1 - Install Turtle

$ npm install -g turtle-cli

This step is super simple. Install turtle cli.

Step 2 - Lock in turtle and expo sdk version

$ turtle setup:android --sdk-version 39.0.0

This step is important to make sure the build version expo is using and the one you use locally is the same. Expo versions bump pretty often, so don’t get caught in the rabbit hole in here.

Step 3 - Fetch keypair from expo

To do this, you need to do expo build at least once. This is because expo generates the keypair for you. Honestly, this is much more easier than having to maintain the keystore locally.

$ expo build:android

This will generate the keypairs. To fetch the keypairs locally. You can perform this command at the root of your project.

$ expo fetch:android:keystore

This will generate the keystore files locally.

Step 4 - Make it easy with a Makefile recipe

I have the recipe ready for Android, but I think you can make it for iOS just by changing some bits of code. The contents of the Makefile are below. I usually split out the Makefile and the actual script to make it easier to maintain.

SHELL := /bin/bash

.PHONY local-release:
	@printf "Going to build apk....\n"
	@. && check_if_pid_exists

	@printf "\nCreating dist folder..."
	@. && create_dist_folder
	@printf "Creating the apk..."
	@. && build_android_apk

.PHONY build-apk:
	@. && build_android_apk is the place where all the magic happens. The contents of that file are below:


function check_if_pid_exists() {
    if test -f "$FILE"; then
        echo "$pid"
        kill "${pid}"
        echo $'killed existing python http server running...\n'
        echo $' file does not exist..\n'

function create_dist_folder() {
    echo $'Creating the dist folder..'
    expo export --dev --public-url --force

    echo $'Going to start serving http server inside dist folder..\n'
    cd dist/
    echo $(pwd)
    python3 -m http.server &> /dev/null & pid=$!

    echo "$pid exists for the http server.."
    cd ../
    echo "$pid" >

function build_android_apk() {
    # Local .env
    if [ -f .env ]; then
        # Load Environment Variables
        export $(cat .env | grep -v '#' | awk '/=/ {print $1}')

    turtle build:android \
        --type apk \
        --keystore-path $KEYSTORE_FILE \
        --keystore-alias "${KEYSTORE_ALIAS}" \
        --allow-non-https-public-url \
        --public-url ""

    echo "Going to get the latest file from output dir..."
    file=$(ls -Art /Users/$(USER)/expo-apps/ | tail -n 1)

    echo "$file is the latest apk..."
    cp /Users/$(USER)/expo-apps/$file $(pwd)/local-releases

You need turtle cli and python3 to do this. This is because we are hosting the server content using that. You will need the following variables

Once you have all of these variables plug it into the makefile recipe and perform make local-relase. You should then have your apk ready in local-releases folder which you can drag to the Android simulator and start testing.