Get a Flutter build onto testers' phones in minutes
flutter build hands you an installable binary in one command. Getting that binary onto someone else's phone is where the friction lives — and it is a different problem on each platform. BetaDrop closes the gap: upload the .apk or .ipa, get an install link and QR code, and testers install from their phone's browser. No tester accounts, no store review, no cables — and a guest upload works without signing up.
One codebase, two artifacts, two very different rulebooks. The Android path is genuinely five minutes. The iOS path works just as fast, but only after Apple's signing requirements are met — this page covers both honestly, including the part where we can't help.
Android: from flutter build apk to an installed app
Build a release APK. Debug APKs install fine too, but they are bigger and slower, and testers will judge your app's performance by them.
flutter build apk --release
# artifact:
# build/app/outputs/flutter-apk/app-release.apkBy default Flutter produces one “fat” APK containing native code for every architecture. If size matters — testers on hotel Wi-Fi, a large app — split it per ABI and share only the variant your testers' phones need, which for essentially every phone from the last few years is arm64-v8a:
flutter build apk --release --split-per-abi
# app-arm64-v8a-release.apk <- send testers this one
# app-armeabi-v7a-release.apk
# app-x86_64-release.apkOne signing detail worth getting right on day one: a fresh Flutter project builds release APKs with the debug keystore until you configure a release key in android/app/build.gradle.kts (or build.gradle on projects created before Flutter 3.29). Debug signing installs fine for testing, but Android refuses to update an app over an existing install if the signature changed — so the day you switch to a real keystore, every tester has to uninstall first. Pick the keystore before the first build you share, and if two builds mysteriously refuse to update each other, compare their certificates in the APK signature checker.
Also bump version: in pubspec.yaml before each build you send out — 1.2.0+7 becomes the version name and build number on both platforms. When a tester reports a bug, “which build are you on?” is the first question, and it only has an answer if every distributed build carries a distinct number.
Testers need the APK, not the AAB
flutter build appbundle produces an .aab for Play Store publishing. It is not an installable file — Google Play unpacks it server-side into device-specific APKs, and a phone cannot sideload it. BetaDrop accepts .apk files directly and does not take .aab. Curious what's inside a bundle anyway? The AAB inspector will open it.
The whole Android path, in four steps
- Build a release APK. Run flutter build apk --release. The artifact lands at build/app/outputs/flutter-apk/app-release.apk. Add --split-per-abi if you want smaller per-architecture APKs — send testers the arm64-v8a one.
- Upload the .apk to BetaDrop. Drag the APK onto the upload page — files up to 500 MB on the free tier, and a guest upload needs no account. BetaDrop takes the .apk directly; an .aab cannot be sideloaded.
- Share the link or QR code. Paste the install link into Slack, a ticket, or a release note — or let testers scan the QR code straight off your screen.
- Testers install from the browser. The link downloads the APK on the tester's phone; Android asks once for permission to install apps from the browser, then the build installs directly.
That's it — no Play Console, no developer account, no review queue. One edge case: on company-managed phones, an IT policy can block installing apps from the browser entirely, and no distribution tool gets around device management — those testers need the build whitelisted by their admin or a personal device. One date worth a note: on 30 September 2026 Google starts enforcing Android developer verification on certified devices in Brazil, Indonesia, Singapore and Thailand. Google scopes that first phase to apps installed from the seven participating app stores rather than an APK a tester downloads from a link, and the global rollout that reaches direct installs is slated for 2027 — so if your testers are in those markets, check the current rules before September rather than assuming either way. Want to sanity-check the artifact before sharing? The APK inspector shows the package name, version, permissions and native ABIs straight from the file — and the APK signature checker reads the signing certificate, which the inspector deliberately does not.
iOS: flutter build ipa with an ad-hoc export
First, the prerequisite Flutter's cross-platform pitch tends to gloss over: flutter build ipa only runs on macOS with Xcode installed, because Apple's toolchain does the signing. A Mac in the team or a macOS CI runner is non-negotiable for the iOS half.
Beyond that, iOS needs one extra input: an export options plist telling Xcode this build is for ad-hoc distribution rather than the App Store.Save this as ios/ExportOptions.plist. release-testing is Apple's current name for ad-hoc distribution; the older ad-hoc value was deprecated in Xcode 15.4 and is rejected outright by Xcode 26, so use this on anything recent:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>release-testing</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
</dict>
</plist>Then build:
flutter build ipa --export-options-plist=ios/ExportOptions.plist
# artifact:
# build/ios/ipa/YourApp.ipaHere is the honest caveat, and it applies to every distribution service, ours included: an ad-hoc build installs only on devices whose UDIDs are in the provisioning profile it was signed with. BetaDrop generates the itms-services manifest so the install works straight from Safari, but it cannot bypass Apple's signing — nobody can. Collect UDIDs with the UDID checker (two taps on the tester's phone), and if an install fails, feed the profile to the provisioning profile decoder to see exactly which devices the build covers.
Two more facts to plan around. Apple caps ad-hoc distribution at 100 registered devices per device type per membership year, and removing a device only frees the slot at your annual renewal — so spend UDID slots on people who will actually test. And the tester experience is genuinely painless once their device is registered: they open your BetaDrop link in Safari, tap install, and the app appears on the home screen. No trust step is needed for ad-hoc builds — that dialog belongs to enterprise certificates, a different distribution method with its own rules.
The whole iOS path, in four steps
- Register tester devices. Collect each tester's UDID, add it in the Apple Developer portal, and regenerate your ad-hoc provisioning profile. An ad-hoc build installs only on devices listed in that profile.
- Create an export options plist. Save an ExportOptions.plist in your ios/ folder with the method key set to release-testing (Apple's current name for ad-hoc distribution; the old ad-hoc value is rejected by Xcode 26) and your team ID.
- Build the IPA. Run flutter build ipa --export-options-plist=ios/ExportOptions.plist. The signed .ipa lands under build/ios/ipa/.
- Upload and share. Upload the .ipa to BetaDrop. It generates the itms-services manifest automatically, so a registered tester installs straight from Safari — no TestFlight, no cable.
Publish from CI on every merge
Once the manual path works, automate it. The BetaDrop CLI reads BETADROP_TOKEN from the environment in CI, and --ci prints only the install URL — ready to post to Slack or a PR comment. A minimal GitHub Actions job for a Flutter app:
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
- run: flutter build apk --release
- name: Publish to BetaDrop
id: betadrop
run: |
npm install -g @betadrop/cli
url="$(betadrop publish build/app/outputs/flutter-apk/app-release.apk --ci)"
echo "install-url=$url" >> "$GITHUB_OUTPUT"
env:
BETADROP_TOKEN: ${{ secrets.BETADROP_TOKEN }}The iOS variant is the same job on a macOS runner: run flutter build ipa with your export options plist and point betadrop publish at build/ios/ipa/*.ipa instead. Getting signing certificates onto a macOS runner is its own project — budget an afternoon for it the first time.
Create the token under Settings → Developer → API tokens on betadrop.app and add it as a repository secret. The GitHub Actions guide goes deeper on the CI workflow, and a packaged one-step Action is being prepared for the GitHub Marketplace. Everything else about the CLI lives on the CLI page.
When BetaDrop isn't the right call
Already deep in Firebase? Use Firebase App Distribution. If your Flutter app ships Crashlytics and the rest of the Firebase SDK, and you want managed tester groups with release notes in the console you already live in, Firebase App Distribution is the coherent choice — the distribution step sits next to your crash reports. BetaDrop's trade is the opposite: no SDK, no tester onboarding, just a link — better when your testers are clients, executives, or anyone you can't ask to accept an invitation first.
Need Play Store parity? Use Play Internal Testing. A sideloaded APK is not the artifact Google Play delivers. If you need to test the exact store experience — the .aab unpacked by Play into device-specific splits, Play App Signing, in-app updates, pre-launch checks — an internal testing track on the Play Console is the only honest rehearsal. Use BetaDrop for the fast iteration loop before that, not instead of it.
Tester sitting next to you? You need no tool at all. For one device on your desk, flutter install or adb install app-release.apk over USB beats any upload, and flutter run --release on a cabled iPhone skips the export dance entirely. Distribution services earn their keep the moment the phone is not in the room.
Where BetaDrop fits: the daily loop of getting a build in front of a human. Files up to 500 MB on the free tier, both platforms in one dashboard, and the tester's entire job is tapping a link. For the iOS-specific comparison, see how this compares to TestFlight.
Frequently asked questions
How do I share a Flutter APK with testers?
Run flutter build apk --release, grab app-release.apk from build/app/outputs/flutter-apk/, and upload it to BetaDrop. You get an install link and a QR code to send to testers; they install directly from their phone's browser with no Play Store listing and no tester accounts. Files up to 500 MB are supported on the free tier.
Can testers install a Flutter app bundle (.aab)?
No. An .aab is a publishing format for Google Play, not an installable file — Play uses it to generate device-specific APKs, and a phone cannot sideload it. For direct distribution to testers, build an APK with flutter build apk instead. BetaDrop accepts .apk and .ipa files, not .aab.
Why won't my Flutter IPA install on a tester's iPhone?
Almost always because the device's UDID is not in the provisioning profile the build was signed with. Ad-hoc builds install only on devices listed in the profile. Collect the tester's UDID, add it in the Apple Developer portal, regenerate the profile, and rebuild with flutter build ipa. BetaDrop distributes the build but cannot bypass Apple's signing rules.
Do testers need an account to install a Flutter build?
No. Testers open the link on their phone and install from the browser — no BetaDrop account, no TestFlight invitation, no Google account. You don't need an account to try it either: a guest upload works without signing up, though guest links expire after 24 hours. Signed-in links default to 3 days and can be extended to 30 days on the free tier.
Is BetaDrop free for Flutter app distribution?
Yes. The free tier is a real price, not a trial: uploads up to 500 MB per file, install links with QR codes, and Android and iOS builds from the same dashboard. Paid plans mainly extend how long build links stay live.
Your build is sitting in build/ right now
Upload it and send the link. The whole round trip — build directory to a tester's home screen — is shorter than reading this page was.