AppForShare

How to share a Flutter build with testers (APK and IPA)

· 7 min read

How to share a Flutter build with testers (APK and IPA)

A Flutter project gives you two very different files to hand to testers: an .apk for Android and an .ipa for iPhone. The Android side is mostly a single command. The iOS side depends on how the build is signed, and that is where most "it will not install" messages come from. This guide covers both, from the build command to a link a tester can open on the phone.

What testers can actually install

Before running any command, it helps to know which outputs can be installed from a link and which cannot:

OutputCommandInstalls from a link?
Universal APKflutter build apkYes, on any supported Android phone
Split APKs per ABIflutter build apk --split-per-abiYes, if the tester gets the APK that matches the phone
App bundle (.aab)flutter build appbundleNo, an .aab is for Google Play, not for phones
IPA exported Ad Hoc, Development or Enterpriseflutter build ipa --export-method ad-hoc (or development, enterprise)Yes, on devices the profile allows
IPA exported for the App Storeflutter build ipaNo, only through TestFlight or the App Store

Android: build a test APK

Universal or split?

Running flutter build apk produces one "fat" APK at build/app/outputs/flutter-apk/app-release.apk. It contains native code for every target ABI, so it is larger, but every tester can install the same file. That is usually the right choice for test builds.

Running flutter build apk --split-per-abi produces one smaller APK per ABI in the same folder:

  • app-armeabi-v7a-release.apk for older 32 bit ARM phones
  • app-arm64-v8a-release.apk for almost every current phone
  • app-x86_64-release.apk for x86 emulators and a few Chromebooks

Split APKs are worth it when the universal file is large and your testers all use modern phones. In that case share the arm64-v8a file. If you share the wrong split, the phone refuses it with a message that the app is not compatible with the device.

Signing the release APK

A new Flutter project signs the release build type with the debug key until you add your own signing config in android/app/build.gradle.kts (or build.gradle). A debug signed APK installs fine for testing, but it has two side effects. Google Play will not accept it, and a phone that already has the app installed with a different key will refuse the update. Signing test builds with the same upload key you use for releases avoids that later. The details are in Android app signing for APK, AAB and sideloading.

Why not the app bundle?

flutter build appbundle is what you upload to Google Play. Play turns it into device specific APKs. A phone cannot install an .aab directly, so for testing outside Play, always share an APK.

iOS: build an Ad Hoc IPA

An iPhone only installs an app from a link when the build is signed for that device. For a typical test round that means Ad Hoc: the UDID of every test device is listed in the provisioning profile. Development signing works the same way for your own team's devices, and Enterprise signing is for in-house apps of companies in the Apple Developer Enterprise Program.

Step 1: register the test devices

Collect each tester's UDID and add it in the Apple Developer portal under Devices. Testers can read their UDID with the free UDID finder from Safari, without a cable or a Mac. After adding devices, the Ad Hoc profile has to be regenerated so it includes them. The full flow is in iOS Ad Hoc device registration.

Step 2: export with the right method

By default flutter build ipa exports for the App Store. Flutter's documentation lists an --export-method option for other kinds of distribution:

flutter build ipa --export-method ad-hoc

The archive lands in build/ios/archive/ and the exported IPA in build/ios/ipa/.

For repeatable builds, especially in CI, an export options file gives you more control:

flutter build ipa --export-options-plist=ios/ExportOptions.plist

A minimal file looks like this. Since Xcode 15.4 the method names in this file changed: ad-hoc became release-testing and development became debugging. The old names now produce a deprecation warning, so use the new ones if your Xcode is current.

<?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>

With automatic signing, Xcode picks or creates an Ad Hoc profile that includes the registered devices. With manual signing, add a provisioningProfiles dictionary that maps your bundle id to the name of the Ad Hoc profile.

Step 3: check the IPA before you send it

Most iOS install failures are visible in the file itself. Drop the IPA into the IPA inspector. It reads the file in your browser without uploading it and shows the distribution type, the profile's expiry date and the list of provisioned UDIDs. If the type says App Store, or a tester's UDID is missing, fix that before sharing.

Share the build with a link

With the APK and IPA ready, the sharing part is the same for both platforms on AppForShare:

  1. Upload the .apk or .ipa on the home page or in your dashboard.
  2. Copy the install link or show the QR code.
  3. Testers open the link on the phone and install over the air.

On Android, the tester allows installs from unknown sources for the browser once in the phone settings. On iPhone, the install works only if the device is in the profile, which is why steps 1 to 3 matter.

If you build on every merge, add the upload to your pipeline instead of doing it by hand:

flutter build apk
npx --yes appforshare@1 upload build/app/outputs/flutter-apk/app-release.apk --notes "Checkout screen redesign"

The CLI needs an API token from Dashboard, Settings (Pro and Team plans) in the APPFORSHARE_TOKEN environment variable. More pipeline examples are in uploading builds from CI and the CI docs.

Common Flutter install problems

The iOS app opens and closes right away

You probably shared a debug build. Flutter's documentation notes that on iOS 14 and later, debug mode Flutter apps can only be launched from Flutter tooling, an IDE or Xcode. Launched from the home screen, they quit. Share a release or profile build instead; flutter build ipa builds in release mode.

"This app cannot be installed because its integrity could not be verified"

On iPhone this nearly always means the device is not in the provisioning profile, the profile has expired, or the build was exported for the App Store. Check all three in the IPA inspector. Adding a UDID does nothing for an IPA you already exported: register the device, regenerate the profile, then build and export again. More causes are covered in can't install an app on an iOS device.

Development builds ask for Developer Mode

If you export with the development method, testers on iOS 16 and later need Developer Mode turned on. They find it under Settings, Privacy and Security, Developer Mode, and the phone restarts to apply it. For people outside your team, Ad Hoc is usually the easier route.

"App not installed" on Android

The most common cause is a signature conflict: the phone has a copy of the app signed with a different key, for example a debug build from flutter run, and the new APK is signed with your release key. Android will not update an app across keys. The tester has to uninstall the old copy first. The second cause is a split APK for the wrong ABI; share the universal APK if in doubt.

The upload is refused

If you upload an .aab, it is the wrong format for testers; build an APK. Large universal APKs and IPAs with many frameworks can also pass the file size limit of a plan: 50 MB for guests, 150 MB on Free, 2 GB on Pro and 4 GB on Team. The pricing page lists every limit.

Before each test round

  • Bump version in pubspec.yaml (the part after + is the build number), so testers can tell builds apart.
  • Point the build at your test backend, for example with --dart-define values.
  • Write two or three lines of release notes: what changed and what to test.
  • Check the IPA in the inspector and the APK in the APK analyzer, which also flags a debuggable or debug signed build.

Share your next Flutter build

AppForShare gives every .apk and .ipa an install link and a QR code, so Android and iPhone testers install the same way. Builds uploaded to an account also get a store readiness check and a "what changed" comparison with the previous build, which is guidance and not a promise of store approval. The Free plan keeps links for 7 days; Pro at $12 a month adds CI uploads, release notes and links that stay live while you are subscribed. Create a free account and upload your first build.

Keep reading

App Distribution Platform · · 9 min read

AppForShare.io vs Competitors - A Comparative Analysis

For small teams and startups, selecting a mobile app testing platform is a critical crossroad. This choice is more than a mere selection: it’s a strategic decision that directly impacts the...