How to build iOS and Android apps without managing CI runners

Run iOS builds on Depot macOS runners, Android builds on Linux, and accelerated Android Emulator tests in Depot CI. Keep your build tools without maintaining a runner fleet.

Last updated 2026-09-26

You can build iOS and Android apps on Depot without maintaining Macs or Linux runners. Use Depot's managed macOS runners for Xcode builds and Linux runners for Android builds with Gradle. If your Android tests need an emulator with KVM acceleration, run that job in Depot CI.

Depot's GitHub Actions runners execute jobs scheduled by GitHub Actions. Depot CI has its own workflow engine and runs GitHub Actions YAML in Depot sandboxes. That distinction affects where you put the workflow and which machine features it can use.

JobWhere to run itWhat you configure
iOS build or simulator testDepot macOS runner in GitHub ActionsXcode version, scheme, SDK, and simulator destination
Android build or JVM unit testDepot Linux runner in GitHub Actions, or a Linux sandbox in Depot CIJDK, Android SDK, and Gradle tasks
Android Emulator test requiring KVMLinux sandbox in Depot CIAndroid SDK, emulator system image, virtual device, and test tasks
Signed releaseThe environment for the corresponding platformSigning credentials and store upload steps

Connect your repository to Depot runners

Follow the GitHub Actions quickstart to connect your Depot organization to GitHub and install the Depot GitHub App. Your GitHub organization may need to approve access to private repositories.

Keep the workflow in .github/workflows/. For an existing iOS job, switch its runs-on label to a supported Depot macOS label. For an Android build job, use a Depot Ubuntu label. The runner reference lists the available operating systems and installed software.

Build an iOS app on macOS

This example builds an iOS app for the simulator. It doesn't need distribution signing credentials. Replace Example.xcworkspace and Example with your workspace and shared scheme, and include your project's dependency installation steps before the build.

name: iOS build

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  ios:
    runs-on: depot-macos-15
    steps:
      - uses: actions/checkout@v4
      - name: Inspect Xcode
        run: xcodebuild -version
      - name: Build for the simulator
        run: |
          xcodebuild \
            -workspace Example.xcworkspace \
            -scheme Example \
            -configuration Debug \
            -sdk iphonesimulator \
            -destination 'generic/platform=iOS Simulator' \
            CODE_SIGNING_ALLOWED=NO \
            build

If you use an Xcode project without a workspace, replace -workspace Example.xcworkspace with -project Example.xcodeproj. Make sure the scheme is shared and committed so CI can find it.

Check the selected Xcode version against your app's requirements. An OS label doesn't pin Xcode to a particular version. Use DEVELOPER_DIR to select an installed Xcode when you need one, and verify its path on the runner.

To run simulator tests, use xcodebuild test with a specific simulator destination available on that image. xcrun simctl list devices available shows the installed devices. The generic destination in the build example compiles the app; it doesn't boot a simulator or run tests.

Depot manages the Mac infrastructure. You still own your app's dependencies, signing, and release process. macOS capacity can queue during periods of high demand, so include queue time when comparing CI providers.

Build and unit test an Android app on Linux

This workflow assumes a Gradle wrapper in the repository root and an Android application module named app. It builds a debug APK and runs JVM unit tests. These tasks don't require an Android Emulator.

name: Android build

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  android:
    runs-on: depot-ubuntu-24.04
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '17'
      - name: Build and run unit tests
        run: ./gradlew :app:assembleDebug :app:testDebugUnitTest --build-cache

Use the JDK version required by your Android Gradle Plugin. Check that the runner image has your project's Android SDK platform and build tools, or install them before running Gradle. Change the module and task names for your project's build variants. The debug APK is normally written under app/build/outputs/apk/; add an artifact upload step if you want to download it after the job finishes.

Depot Cache supports Gradle. On Depot GitHub Actions runners, the remote cache connection is configured automatically when Allow Actions jobs to automatically connect to Depot Cache is enabled in your organization settings. Enable Gradle's build cache with --build-cache or org.gradle.caching=true in gradle.properties. Reusable task outputs can then come from the shared cache instead of being rebuilt on every fresh runner. Check Gradle's FROM-CACHE task results to see what's being reused.

Run Android Emulator tests in Depot CI

Instrumented tests need a device or emulator. Depot GitHub Actions runners don't expose /dev/kvm. Depot CI's Linux sandboxes provide it by default, so use Depot CI for Android Emulator jobs that require hardware acceleration. See the KVM troubleshooting guide.

Start with the Depot CI quickstart. Workflows live in .depot/workflows/ and use GitHub Actions YAML. A depot-ubuntu-24.04 label in that directory selects a Depot CI sandbox; the same label in .github/workflows/ selects a managed GitHub Actions runner. Moving the workflow changes who schedules it and the environment it runs in.

Configure the emulator job to install the required JDK and Android SDK packages, create an Android Virtual Device, start it, and wait for it to finish booting. Then run your instrumented test task, such as ./gradlew :app:connectedDebugAndroidTest. That Gradle command expects a connected device; it doesn't create an emulator for you. Keep emulator logs and test reports as artifacts so a failed test is easier to diagnose.

Keep the iOS job on Depot's managed macOS runners in GitHub Actions. The Linux sandbox used for the Android job can't run Xcode.

Add signing and release steps

Get unsigned builds and tests working before adding store credentials. For iOS distribution, configure your Apple signing certificate and provisioning profile, archive the app, and export it for the intended distribution method. For Android, configure the release keystore and build your signed APK or Android App Bundle. Uploads to TestFlight, the App Store, or Google Play are separate workflow steps.

Keep signing credentials in your CI secret store and restrict release jobs to trusted branches or manual approval. If you move an Android release job to Depot CI, move its secrets into Depot CI settings too. A runner change doesn't transfer secrets between CI systems or replace your store accounts.

Compare the same app commit, toolchain, and test suite when evaluating the move. Record queue time, build time, test time, cache reuse, and the cost of the complete workflow. Run both a cold build and a repeat build so a warm cache doesn't hide missing dependencies or an expensive first run.

Start building with Depot
in minutes