How to Distribute Flutter Apps to Testers

Flutter lets you build for iOS and Android from one codebase. But when it comes to getting those builds into your testers’ hands, the story gets complicated fast. Your Android build produces an APK. Your iOS build produces an IPA. And the default distribution paths—TestFlight for iOS, Google Play Internal Testing for Android—each come with their own friction, delays, and platform lock-in.

What if you could upload both your APK and IPA to one place, send a single link to your testers, and get feedback the same day? That’s what TestApp.io is built for.

In this guide, we’ll walk through the full workflow: building your Flutter app for both platforms, uploading to TestApp.io (via the portal, CLI, or CI/CD), and getting your testers up and running in minutes—not days.

The Problem with Flutter Beta Distribution

Flutter’s cross-platform promise breaks down at distribution time. Here’s what you’re up against:

  • TestFlight is iOS-only. It requires Apple Developer Program membership, App Store Connect setup, and a review process that can take up to 48 hours for builds with significant changes. External testers are capped at 10,000, but internal testers are limited to just 25 per app. And there’s no Android story at all.
  • Google Play Internal Testing is slow. While internal test tracks skip the review process, the setup requires a Google Play Developer account, and testers need a Google account to opt in. New personal developer accounts must complete 14 days of closed testing with at least 12 opted-in testers before they can even publish to production.
  • Firebase App Distribution covers both platforms—but it’s a distribution-only tool. Everything that happens after install—bug reports, task tracking, release sign-offs—lives somewhere else entirely. You end up stitching together Firebase, Jira, Slack, and a spreadsheet.

For a Flutter team shipping to both platforms, managing two separate distribution pipelines is a tax on every release cycle.

A Single Dashboard for Both Platforms

TestApp.io was designed for exactly this scenario. Upload your APK and IPA to one place, invite your testers once, and let them install the right build for their device. No app store accounts required. No review gates. No separate workflows for Android and iOS.

Beyond distribution, TestApp.io gives your testers a way to report bugs directly from the app, log blockers, and track feedback—all tied back to the specific release they’re testing. Your team gets a release dashboard, notification integrations with tools like Slack and Microsoft Teams, and task management that syncs with project management tools such as Jira and Linear.

Step 1: Build Your Flutter App

Before uploading anything, you need your build artifacts. Flutter makes this straightforward.

Build the APK (Android)

From your Flutter project root, run:

flutter build apk --release

This produces a fat APK (all ABIs) at:

build/app/outputs/flutter-apk/app-release.apk
ℹ️
TestApp.io accepts APK files for Android distribution. If you need a smaller APK for testing, you can use flutter build apk --split-per-abi to generate architecture-specific APKs, then upload the one matching your testers’ devices.

Build the IPA (iOS)

Building for iOS requires a Mac with Xcode installed. Run:

flutter build ipa --release --export-method ad-hoc

This generates the IPA at:

build/ios/ipa/<YourApp>.ipa
⚠️
The --export-method ad-hoc flag is important. TestApp.io supports Ad Hoc, Development, and Enterprise signed IPAs. If you omit this flag, Flutter defaults to App Store export, which won’t work for direct distribution. Make sure your provisioning profile includes your testers’ device UDIDs for Ad Hoc builds.

Step 2: Upload to TestApp.io

You have three ways to get your builds onto TestApp.io: the web portal, the CLI, or your CI/CD pipeline. Pick whichever fits your workflow.

Option A: Upload via the Portal

The simplest path—ideal for one-off builds or when you’re just getting started:

  1. Log in to portal.testapp.io
  2. Select your app (or create a new one)
  3. Drag and drop your app-release.apk and .ipa file
  4. Add release notes so your testers know what to test
  5. Hit upload—your team gets notified instantly

That’s it. Testers receive a link, tap to install, and they’re testing your latest Flutter build within minutes.

Option B: Upload via ta-cli

For developers who prefer the command line, ta-cli lets you publish directly from your terminal. Install it first:

curl -Ls https://github.com/testappio/cli/releases/latest/download/install | bash

Then publish both platforms in a single command:

ta-cli publish \\
  --api_token=YOUR_API_TOKEN \\
  --app_id=YOUR_APP_ID \\
  --release=both \\
  --apk=build/app/outputs/flutter-apk/app-release.apk \\
  --ipa=build/ios/ipa/YourApp.ipa \\
  --release_notes="Fixed login bug, improved performance" \\
  --notify

Key flags explained:

  • --release: Set to both, android, or ios depending on what you’re uploading
  • --apk / --ipa: Paths to your build artifacts
  • --release_notes: What changed in this build (up to 1,200 characters)
  • --git_release_notes: Automatically pull the last commit message as release notes
  • --git_commit_id: Include the commit hash in the release notes for traceability
  • --notify: Send push notifications to your team members

You can grab your API token and App ID from your TestApp.io portal under Settings > API Credentials.

Option C: Upload via CI/CD (GitHub Actions)

This is where the real time savings kick in. Automate the entire build-and-distribute pipeline so every push to your main branch delivers a fresh build to your testers.

Here’s a GitHub Actions workflow that builds your Flutter app for both platforms and uploads to TestApp.io:

name: Build & Distribute Flutter App

on:
  push:
    branches: [main]

jobs:
  build-android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
        with:
          flutter-version: "3.x"
      - run: flutter pub get
      - run: flutter build apk --release
      - uses: testappio/github-action@v5
        with:
          api_token: \${{ secrets.TESTAPPIO_API_TOKEN }}
          app_id: \${{ secrets.TESTAPPIO_APP_ID }}
          file: build/app/outputs/flutter-apk/app-release.apk
          release_notes: "Android build from commit \${{ github.sha }}"
          git_release_notes: true
          include_git_commit_id: true
          notify: true

  build-ios:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
        with:
          flutter-version: "3.x"
      - run: flutter pub get
      - run: flutter build ipa --release --export-method ad-hoc
      - uses: testappio/github-action@v5
        with:
          api_token: \${{ secrets.TESTAPPIO_API_TOKEN }}
          app_id: \${{ secrets.TESTAPPIO_APP_ID }}
          file: build/ios/ipa/YourApp.ipa
          release_notes: "iOS build from commit \${{ github.sha }}"
          git_release_notes: true
          include_git_commit_id: true
          notify: true
💡
Store your TESTAPPIO_API_TOKEN and TESTAPPIO_APP_ID as GitHub repository secrets. Never hardcode credentials in your workflow files.

The TestApp.io GitHub Action (testappio/github-action@v5) handles installing ta-cli and uploading each artifact. Since the action accepts a single file per step, the workflow runs Android and iOS as parallel jobs for faster builds.

CI/CD Beyond GitHub Actions

GitHub Actions isn’t the only option. TestApp.io integrates with the CI/CD tools Flutter teams already use:

  • Fastlane — Use the testappio Fastlane plugin to upload as part of your lane. Great if you’re already using Fastlane for code signing and build management.
  • Codemagic — A Flutter-first CI/CD service. Add a post-build script to upload via ta-cli.
  • GitHub Actions — The workflow shown above. Zero configuration beyond secrets.

In every case, the pattern is the same: build your artifacts, then call ta-cli or the TestApp.io action to upload. Your testers get notified, install from a link, and you get feedback—all without touching an app store.

How TestApp.io Compares

Here’s an honest look at how the main distribution options stack up for Flutter teams:

TestApp.io TestFlight Google Play Internal Testing Firebase App Distribution
Android support✅ APK upload❌ iOS only✅ APK + AAB✅ APK + AAB
iOS support✅ IPA upload✅ Native❌ Android only✅ IPA upload
Review requiredNoYes (up to 48h)No (internal track)No
Tester setupEmail invite + linkApple ID requiredGoogle account + opt-inEmail invite
In-app feedback✅ Built-inBasic screenshots❌ None❌ None
Task management✅ Built-in + Jira/Linear sync❌ None❌ None❌ None
Notification integrations✅ Slack, Teams, emailEmail onlyEmail onlyEmail + Firebase console
CLI support✅ ta-cli✅ Xcode CLI✅ Gradle✅ Firebase CLI
CI/CD integrationsGitHub Actions, Fastlane, Codemagic, + moreXcode Cloud, FastlaneGradle-basedFastlane, GitHub Actions
Both platforms, one dashboard

TestFlight remains the gold standard for iOS-only teams that need tight App Store integration. Firebase App Distribution is a solid choice if your stack is already Firebase-heavy. But for Flutter teams shipping to both platforms, managing a single distribution pipeline saves real time.

Tips for a Smooth Flutter Testing Workflow

A few things we’ve seen work well for teams distributing Flutter apps:

  • Automate from day one. Even a simple GitHub Actions workflow that builds on push to main eliminates the "Can you send me the latest build?” messages from your Slack channel.
  • Use release notes consistently. The --git_release_notes flag in ta-cli automatically pulls the last commit message. It takes zero effort and gives testers context on what changed.
  • Keep your provisioning profiles updated. For iOS Ad Hoc distribution, every tester’s device UDID needs to be in your provisioning profile. TestApp.io helps you collect UDIDs from your team, but the profile itself needs to be regenerated in Apple Developer Portal whenever you add new devices.
  • Test the release build, not debug. Always distribute --release builds. Debug builds behave differently—they’re slower, include debug banners, and may not surface issues that only appear in release mode.
  • Parallel CI jobs save time. Since Android builds run on Linux and iOS builds require macOS, run them as parallel jobs in your CI pipeline. There’s no reason to build them sequentially.

Get Started

If you’re building with Flutter and tired of juggling TestFlight, Play Console, and a patchwork of tools to get builds to your testers—give TestApp.io a try. Upload your APK and IPA, invite your team, and start collecting feedback today.

Already have a CI/CD pipeline? Check out the GitHub Actions setup guide to plug in TestApp.io in under five minutes.

Have questions about integrating TestApp.io into your Flutter workflow? Check our pricing page for plan details, or reach out—we’re happy to help.