Back to Blog

Mobile CI/CD with GitHub Actions: Build and Deploy Any App to AutoDevice

A complete guide to building and deploying mobile apps to AutoDevice using GitHub Actions. Covers native Android, native iOS, React Native, Flutter, and Expo with 16 working demo repos you can clone and go.

By Team AutoDevice

Mobile CI/CD with GitHub Actions: Build and Deploy Any App to AutoDevice

Every mobile framework has its own build toolchain, and wiring it into CI/CD can feel like a scavenger hunt. This guide covers every major mobile stack — native Android, native iOS, React Native, Flutter, and Expo — showing you how to build your app in GitHub Actions and upload it to AutoDevice on every push.

We’ve created 16 working demo repos (one for each framework/platform/build-tool combo) so you can clone, add your API key, and go.

The Upload Step

Every workflow ends the same way. Once you have a build artifact (an APK or a zipped .app bundle), upload it with the autodevice/upload-action:

- name: Upload to AutoDevice
  uses: autodevice/upload-action@main
  with:
    api-key: ${{ secrets.AUTODEVICE_API_KEY }}
    package-name: your.bundle.id
    build-path: path/to/your/artifact

Add your AUTODEVICE_API_KEY under Settings > Secrets in your GitHub repo. That’s it for the upload side. Everything below is about producing the artifact.

Native Android

Runner: ubuntu-latest | Needs: JDK 17

The build step is one line with Gradle, or two lines if you use Fastlane:

ApproachBuild commandDemo
Gradle./gradlew assembleDebugandroid-gradle-ci-demo
Fastlanebundle exec fastlane android buildandroid-fastlane-ci-demo

Artifact path: app/build/outputs/apk/debug/app-debug.apk

Fastlane adds Ruby setup (ruby/setup-ruby@v1) and a Gemfile, but under the hood it’s still calling gradle(task: "assembleDebug").

Native iOS

Runner: macos-15 | Needs: Xcode 16.4

All iOS examples build for the simulator with code signing disabled (CODE_SIGN_IDENTITY="" CODE_SIGNING_ALLOWED=NO), so no provisioning profiles are needed in CI.

ApproachBuild commandDemo
xcodebuildxcodebuild build -project ... -sdk iphonesimulatorios-xcodebuild-ci-demo
Fastlanebundle exec fastlane ios buildios-fastlane-ci-demo

Artifact: The .app bundle from build/Build/Products/Debug-iphonesimulator/, zipped before upload.

React Native

React Native adds Node.js + npm on top of the platform-specific toolchain. iOS builds also require CocoaPods (pod install before building).

PlatformApproachRunnerDemo
AndroidGradleubuntu-latestreact-native-android-ci-demo
AndroidFastlaneubuntu-latestreact-native-fastlane-android-ci-demo
iOSxcodebuildmacos-15react-native-ios-ci-demo
iOSFastlanemacos-15react-native-fastlane-ios-ci-demo

Key difference from native: React Native iOS uses a .xcworkspace (generated by CocoaPods), not a .xcodeproj.

Android artifact: android/app/build/outputs/apk/debug/app-debug.apk iOS artifact: Zipped .app from build/Build/Products/Debug-iphonesimulator/

The Fastlane iOS variant (react-native-fastlane-ios-ci-demo) also demonstrates a production-ready caching setup with three cache layers: ccache, CocoaPods, and DerivedData.

Flutter

Flutter uses subosito/flutter-action@v2 to install the SDK. The build commands are straightforward:

  • Android: flutter build apk --debug
  • iOS: flutter build ios --simulator --debug
PlatformApproachRunnerDemo
AndroidFlutter CLIubuntu-latestflutter-android-ci-demo
AndroidFastlaneubuntu-latestflutter-fastlane-android-ci-demo
iOSFlutter CLImacos-15flutter-ios-ci-demo
iOSFastlanemacos-15flutter-fastlane-ios-ci-demo

Android artifact: build/app/outputs/flutter-apk/app-debug.apk iOS artifact: Zipped Runner.app from build/ios/iphonesimulator/

Gotcha: Flutter’s Fastlane Android variant may need a gradle wrapper step if your android/ directory doesn’t ship a gradlew.

Expo

Expo has two build modes:

  • EAS Build (cloud) — builds happen on Expo’s servers. You wait for the result and download the artifact. iOS cloud builds can even run on an ubuntu-latest runner since Xcode isn’t needed locally.
  • EAS Build —local — builds run on your CI runner. Needs JDK (Android) or macOS + Xcode (iOS), but gives you full control and avoids EAS queue times.

Both require an EXPO_TOKEN secret for authentication.

PlatformModeRunnerDemo
AndroidEAS Cloudubuntu-latestexpo-eas-android-ci-demo
AndroidEAS Localubuntu-latestexpo-local-android-ci-demo
iOSEAS Cloudubuntu-latestexpo-eas-ios-ci-demo
iOSEAS Localmacos-15expo-local-ios-ci-demo

Cloud builds use eas build --platform <ios|android> --profile <profile> --wait then download the artifact via eas build:list. Local builds use eas build --local --output app.apk and write the artifact directly.

Android builds need a debug keystore and credentials.json generated in CI. iOS simulator builds need a simulator profile in eas.json:

{
  "build": {
    "simulator": {
      "ios": { "simulator": true }
    },
    "preview": {
      "android": { "buildType": "apk", "credentialsSource": "local" },
      "distribution": "internal"
    }
  }
}

Summary

FrameworkPlatformBuild ToolRunnerDemo
Native AndroidAndroidGradleubuntu-latestlink
Native AndroidAndroidFastlaneubuntu-latestlink
Native iOSiOSxcodebuildmacos-15link
Native iOSiOSFastlanemacos-15link
React NativeAndroidGradleubuntu-latestlink
React NativeAndroidFastlaneubuntu-latestlink
React NativeiOSxcodebuildmacos-15link
React NativeiOSFastlanemacos-15link
FlutterAndroidFlutter CLIubuntu-latestlink
FlutterAndroidFastlaneubuntu-latestlink
FlutteriOSFlutter CLImacos-15link
FlutteriOSFastlanemacos-15link
ExpoAndroidEAS Cloudubuntu-latestlink
ExpoAndroidEAS Localubuntu-latestlink
ExpoiOSEAS Cloudubuntu-latestlink
ExpoiOSEAS Localmacos-15link

Every linked repo has a passing CI workflow. Clone one, add your AUTODEVICE_API_KEY secret, and you’re up and running.