Skip to content

React Native with GitHub Codespaces

GitHub Codespaces provides a powerful, cloud-based development environment accessible directly from your browser. This makes it an excellent choice for React Native development, especially for Android builds, as it eliminates complex local setup, reduces resource usage on your machine, and ensures a consistent environment across devices.

Prerequisites

Whether setting up manually or using a Dev Container, your environment will need:

  • Node.js: Multiple versions are usually available (e.g., v18, v20). The Dev Container approach explicitly installs a version (e.g., LTS). For manual setup, you might need to switch versions using tools like nvm.
  • Java Development Kit (JDK): Required for Android development (e.g., OpenJDK 17 or 21). The Dev Container explicitly installs a version (e.g., 17). For manual setup, it’s usually pre-installed in the base Codespace image.

You have two main options for setting up the Android-specific tools (SDK, build tools, NDK): automating it with a Dev Container configuration or setting it up manually within the Codespace.

This approach uses GitHub Codespaces’ built-in container configuration to automatically set up the necessary Android environment when your Codespace is created or rebuilt. This is generally faster and less error-prone than manual setup.

  1. Create the Dev Container Configuration Files

    In the root of your project repository, create a folder named .devcontainer. Inside this folder, create two files:

    a. devcontainer.json: This file defines the Codespace environment, including the base image, features (like Node.js and Java), and commands to run after the container is created.

    .devcontainer/devcontainer.json
    {
    "name": "React Native Android Dev Environment",
    "image": "mcr.microsoft.com/devcontainers/base:ubuntu", // Base Ubuntu image
    "features": {
    // Installs specified Java version
    "ghcr.io/devcontainers/features/java:1": {
    "version": "17" // Or "21", "11", etc., matching project needs
    // "jdkDistro": "ms" // Optional: specify distribution
    },
    // Installs Node.js (LTS version)
    "ghcr.io/devcontainers/features/node:1": {
    "version": "lts"
    }
    // Add more features if needed (e.g., Docker, databases)
    },
    // Optional: Define minimum host machine requirements
    "hostRequirements": {
    "cpus": 4,
    "memory": "16gb",
    "storage": "32gb"
    },
    "customizations": {
    "vscode": {
    "extensions": [
    // Add useful VS Code extensions
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "msjsdiag.vscode-react-native",
    "eamodio.gitlens"
    ]
    }
    },
    // Command to run *after* the container is created and features are installed
    // Runs the setup script and then installs project dependencies
    "postCreateCommand": "bash .devcontainer/setup.sh && npm install",
    "remoteEnv": {
    // Example: Define environment variables needed by your app/build
    // "MY_API_KEY": "your-key-here" // Use Codespace Secrets for sensitive values
    }
    }

    b. setup.sh: This script, referenced in postCreateCommand, handles the download, installation, and configuration of the Android SDK components.

    .devcontainer/setup.sh
    #!/bin/bash
    set -e # Exit immediately if a command exits with a non-zero status.
    # Store the original working directory (should be the workspace root)
    ORIGINAL_DIR=$(pwd)
    echo "--- Starting Android SDK setup in ${ORIGINAL_DIR} ---"
    # 1. Define SDK installation directory within the container's home
    SDK_DIR="/home/vscode/android-sdk"
    echo "Target SDK Installation directory: ${SDK_DIR}"
    mkdir -p "${SDK_DIR}" # Ensure SDK root directory exists
    # Use a temporary directory for download and unzip
    TEMP_DIR=$(mktemp -d)
    echo "Working temporarily in ${TEMP_DIR}"
    cd "${TEMP_DIR}" # Change into temp dir
    # 2. Download the latest command-line tools
    # Note: Check for the latest URL/version if this script fails years later
    CMDLINE_TOOLS_URL="https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip"
    echo "Downloading command-line tools from ${CMDLINE_TOOLS_URL}..."
    curl -fsSL -o commandlinetools.zip "${CMDLINE_TOOLS_URL}"
    # 3. Unzip the tools
    echo "Unzipping tools..."
    unzip -q commandlinetools.zip
    # 4. Prepare final SDK structure directory
    mkdir -p "${SDK_DIR}/cmdline-tools"
    # 5. Move the unzipped 'cmdline-tools' directory to the final location
    echo "Moving tools to final destination: ${SDK_DIR}/cmdline-tools/latest"
    # The unzipped folder is named 'cmdline-tools', move its contents
    mv "${TEMP_DIR}/cmdline-tools" "${SDK_DIR}/cmdline-tools/latest"
    # 6. Clean up the temporary directory
    echo "Cleaning up temporary directory ${TEMP_DIR}..."
    # IMPORTANT: Change back to the original directory *before* removing temp dir
    cd "${ORIGINAL_DIR}"
    rm -rf "${TEMP_DIR}"
    echo "Returned to ${ORIGINAL_DIR}"
    # 7. Set Environment Variables for *this script's execution*
    # These help sdkmanager run correctly within this script.
    # Gradle primarily uses the local.properties file (created later).
    echo "Setting temporary environment variables for SDK Manager..."
    export ANDROID_SDK_ROOT="${SDK_DIR}"
    export ANDROID_HOME="${SDK_DIR}" # Some tools might still prefer ANDROID_HOME
    export PATH="${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin:${ANDROID_SDK_ROOT}/platform-tools:${PATH}"
    echo "ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}"
    echo "Updated PATH includes SDK tools temporarily"
    # Define the path to sdkmanager
    SDKMANAGER="${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager"
    # 8. Verify sdkmanager
    echo "Verifying sdkmanager..."
    "${SDKMANAGER}" --version
    # 9. Accept licenses automatically
    echo "Accepting licenses..."
    yes | "${SDKMANAGER}" --licenses > /dev/null
    # 10. Install required SDK components
    # Adjust versions based on your React Native project requirements
    PLATFORMS_VERSION="android-34"
    BUILD_TOOLS_VERSION="34.0.0"
    # Check React Native docs for the recommended NDK version for your RN version
    NDK_VERSION="26.1.10909125"
    echo "Installing SDK components: platform-tools, platforms;${PLATFORMS_VERSION}, build-tools;${BUILD_TOOLS_VERSION}, ndk;${NDK_VERSION}"
    "${SDKMANAGER}" "platform-tools" "platforms;${PLATFORMS_VERSION}" "build-tools;${BUILD_TOOLS_VERSION}" "ndk;${NDK_VERSION}"
    # 11. Create local.properties for Gradle
    # Assumes an 'android' directory exists at the project root.
    # This tells Gradle where to find the SDK.
    echo "Creating/Updating android/local.properties with SDK path..."
    if [ -d "android" ]; then
    echo "sdk.dir=${SDK_DIR}" > android/local.properties
    echo "Created android/local.properties"
    else
    echo "Warning: 'android' directory not found at project root. Skipping creation of local.properties."
    echo "You may need to create this file manually inside your 'android' directory: echo 'sdk.dir=${SDK_DIR}' > android/local.properties"
    fi
    echo "--- Android SDK setup script finished successfully ---"
    # Optional: Add a reminder about .gitignore
    echo "*** REMINDER: Ensure 'local.properties' is listed in your /android/.gitignore file! ***"
  2. Commit and Push

    Commit the .devcontainer folder and its contents (devcontainer.json, setup.sh) to your GitHub repository.

  3. Rebuild or Create the Codespace

    If you already have a Codespace open for this repository, you’ll need to rebuild it for the changes to take effect. Look for a command palette option (Ctrl+Shift+P or Cmd+Shift+P) like “Codespaces: Rebuild Container”. If you’re creating a new Codespace, it will automatically use this configuration.

    During the build, you’ll see logs indicating that the postCreateCommand is running the setup.sh script and npm install.

  4. Verify Setup

    Once the Codespace is ready, the Android SDK should be installed in /home/vscode/android-sdk, and the android/local.properties file should point to it. You can now proceed directly to the “Developing Your App” section below, skipping Option 2 (Manual Setup). Note that while the setup.sh exports environment variables like ANDROID_HOME, they might not be automatically present in new terminal sessions you open later. However, the local.properties file ensures Gradle can find the SDK, which is the primary requirement for building.

Option 2: Manual Android Environment Setup

If you prefer not to use the Dev Container automation or need more granular control, you can set up the Android SDK manually within an existing Codespace. Note that you will need to repeat these steps if you create a fresh Codespace without the automated setup.

  1. Install Android Command Line Tools

    Create a directory, download, extract, and organize the tools:

    Terminal window
    # Create directory and navigate into it
    mkdir -p ~/android-sdk && cd ~/android-sdk
    # Download the latest command line tools (check for updated URLs if needed)
    # URL might change, verify at https://developer.android.com/tools/releases/platform-tools
    wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
    # Unzip and structure the tools correctly
    unzip commandlinetools-linux-*.zip
    mkdir -p cmdline-tools/latest
    mv cmdline-tools/* cmdline-tools/latest/ 2>/dev/null || true # Handles potential existing files
    rm commandlinetools-linux-*.zip # Clean up downloaded zip
    # Return to your project directory (adjust path if needed)
    cd ~/workspaces/* # Or your specific project path
  2. Configure Environment Variables

    Set the ANDROID_HOME variable and add the SDK tools to your PATH so they can be found by the system and React Native CLI. You also need to create local.properties for Gradle.

    Terminal window
    # Add environment variables to your shell configuration file (e.g., .bashrc or .zshrc)
    echo '# Android SDK' >> ~/.bashrc
    echo 'export ANDROID_HOME=$HOME/android-sdk' >> ~/.bashrc
    echo 'export ANDROID_SDK_ROOT=$HOME/android-sdk' >> ~/.bashrc # Some tools use this
    echo 'export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools' >> ~/.bashrc
    # Apply the changes to your current session
    source ~/.bashrc
    # Create local.properties for Gradle (run from project root)
    if [ -d "android" ]; then
    echo "sdk.dir=$HOME/android-sdk" > android/local.properties
    echo "Created/Updated android/local.properties"
    echo "*** REMINDER: Ensure 'local.properties' is listed in your /android/.gitignore file! ***"
    else
    echo "Warning: 'android' directory not found. Cannot create local.properties."
    fi
  3. Install SDK Components

    Use the sdkmanager tool (now in your PATH) to accept licenses and install the required Android SDK platforms, build tools, and other necessary components.

    Terminal window
    # Accept all SDK licenses
    yes | sdkmanager --licenses
    # Install required components (adjust versions as needed for your project)
    # Check React Native docs for recommended NDK version
    sdkmanager \
    "platform-tools" \
    "platforms;android-34" \
    "build-tools;34.0.0" \
    "ndk;26.1.10909125"

Developing Your App

Whether you used the automated or manual setup, you can now work on your React Native project.

Initializing a New Project

If starting fresh, use the React Native CLI:

Terminal window
# Replace YourProjectName with your desired project name
npx @react-native-community/cli init YourProjectName
cd YourProjectName
# If using manual setup & just initialized, create local.properties now:
# echo "sdk.dir=$HOME/android-sdk" > android/local.properties

Building for Debug

  1. Install Dependencies (if not already done by postCreateCommand in Dev Container)

    Navigate to your project’s root directory and run:

    Terminal window
    npm install
    # or yarn install
  2. Prepare and Build Android Debug APK

    Terminal window
    cd android
    # Ensure gradlew script is executable (NEEDED regardless of setup method)
    chmod +x gradlew
    ./gradlew clean # Optional: Clean previous builds
    ./gradlew assembleDebug # Build the debug APK

    The debug APK will be located at android/app/build/outputs/apk/debug/app-debug.apk. You can download this file via the Codespaces file explorer (usually in the left sidebar under the “Explorer” tab) to install on a physical device or an emulator. Right-click the file and choose “Download…”.

Running and Debugging on a Device

  1. Start the Metro Bundler

    In your project’s root directory, start the Metro bundler which serves your JavaScript code:

    Terminal window
    npx react-native start
  2. Forward the Metro Port (8081)

    GitHub Codespaces should automatically detect port 8081 being used. Go to the Ports tab in VS Code (usually at the bottom panel next to Terminal, Problems, etc.). Find port 8081, right-click it, set Port Visibility to Public, and copy the Forwarded Address. It will look something like https://your-codespace-name-random-string-8081.app.github.dev.

  3. Connect Your Physical Android Device

    • Install the app-debug.apk (downloaded previously) on your device.
    • Ensure your device is connected to the same network as your computer (though technically it just needs internet access to reach the public forwarded URL).
    • Open the app.
    • Open the Developer Menu (usually by shaking the device or running adb shell input keyevent 82 if connected via ADB - though ADB connection to Codespaces is complex and usually not the primary method).
    • Go to Settings (or Dev Settings) > Debug server host & port for device.
    • Enter the Forwarded Address from Step 2, removing the https:// prefix but keeping the port number (e.g., your-codespace-name-random-string-8081.app.github.dev).
    • Go back and select Reload from the Developer Menu. The app should now connect to the Metro server running in your Codespace and load the bundle.

Building for Release

To create a release build suitable for distribution (e.g., Google Play Store), you need to sign your Android app. These steps are manual and required regardless of whether you used the Dev Container or manual SDK setup.

  1. Generate a Signing Key

    Use keytool (part of the JDK installed earlier) to generate a private signing key. Store this keystore file securely and back it up! Do not commit the keystore file to Git.

    Terminal window
    # Navigate to the android/app directory first
    cd android/app
    # Generate the keystore
    keytool -genkeypair -v -keystore release.keystore -alias your-key-alias -keyalg RSA -keysize 2048 -validity 10000

    You will be prompted to create passwords for the keystore and the key. Remember these passwords. Replace your-key-alias with a unique name for your key.

  2. Configure Gradle for Signing

    Edit your android/app/build.gradle file to read the credentials from keystore.properties (or environment variables/secrets) and set up the release signing configuration.

    android/app/build.gradle
    ...
    // Add these lines near the top, outside the android { ... } block
    def keystorePropertiesFile = rootProject.file("app/keystore.properties")
    def keystoreProperties = new Properties()
    if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
    }
    // You could alternatively load from environment variables here
    android {
    ...
    defaultConfig { ... }
    signingConfigs {
    debug {
    // Default debug signing config
    storeFile file('debug.keystore')
    storePassword 'android'
    keyAlias 'androiddebugkey'
    keyPassword 'android'
    }
    release {
    // Read from keystore.properties if it exists
    if (keystorePropertiesFile.exists() && keystoreProperties['storePassword'] != null) {
    storeFile file(keystoreProperties['storeFile'])
    storePassword keystoreProperties['storePassword']
    keyAlias keystoreProperties['keyAlias']
    keyPassword keystoreProperties['keyPassword']
    } else {
    // Optional: Fallback, warning, or fail build if properties missing
    println("Warning: Release keystore properties not found in app/keystore.properties. Release signing disabled.")
    // Or you might want to explicitly disable release signing here or throw an error
    // signingConfig null // Example: disable signing if props missing
    }
    }
    }
    buildTypes {
    debug {
    signingConfig signingConfigs.debug
    ...
    }
    release {
    // Apply the release signing configuration
    signingConfig signingConfigs.release
    // Enable code shrinking, obfuscation, and resource optimization
    minifyEnabled true
    shrinkResources true
    proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
    ...
    }
    }
    ...
    }
  3. Build the Release APK

    Navigate back to the android directory and run the assembleRelease Gradle task:

    Terminal window
    cd .. # Go back to android/ directory if you were in android/app/
    ./gradlew clean
    # This task generates a signed APK if release signing is configured
    ./gradlew assembleRelease

    The signed release APK(s) will be generated in android/app/build/outputs/apk/release/. Download these for distribution.

Optimizing APK Size (Optional: ABI Splitting)

To reduce the app’s download size for users, you can generate separate APKs for different CPU architectures (Application Binary Interfaces - ABIs). Add the following splits block inside the android { ... } block in android/app/build.gradle:

android/app/build.gradle
android {
// ... other configurations like compileSdkVersion, defaultConfig, signingConfigs, buildTypes ...
splits {
abi {
enable true // Enable ABI splitting
reset() // Clear any existing filters
// Specify architectures to build for (common choices shown)
include "armeabi-v7a", "arm64-v8a" // Common for 32-bit and 64-bit ARM phones
// include "x86", "x86_64" // Often needed for emulators or specific devices like Chromebooks
universalApk false // Set to true to ALSO build one large APK containing all ABIs
// Usually set to false when uploading splits to Google Play
}
}
// If using Hermes and ProGuard, ensure NDK is available (handled by setup scripts)
// ... rest of android block ...
}