🚀 flutter_distribute_manager
Build your Flutter app and hand QA a working link — in one command. Android APK + iOS IPA → uploaded to Google Drive and Diawi automatically. No OAuth app to register. No manual Xcode archiving. No dragging files into shared folders.
$ flutter_distribute_manager
━━ flutter_distribute_manager ━━
Project : my_app v1.4.2
? Which platform do you want to build?
1) Android (APK)
2) iOS (IPA)
3) Android + iOS
✔ Built my_app_UAT_2026_06_19_0930_arm64-v8a.apk (24 MB)
✔ Uploaded to Google Drive
🔗 https://drive.google.com/…
🤔 What it replaces
Shipping a build to QA by hand is seven boring steps every time:
| Doing it by hand | With flutter_distribute_manager |
|---|---|
flutter build apk → wait → find the file in build/… |
One command builds it for you |
| Drag the APK into a Google Drive folder | Uploaded automatically |
| Right-click → Get shareable link → copy | Link printed in your terminal |
| Flat Drive folder — chaos after 10 builds | Organised App/Year/Month/ENV/ folders |
| "Which build is this — DEV or PROD?" | Environment stamped into every filename |
| Android and iOS are two separate chores | Both in a single run |
| Paste the link into Slack yourself | Optional auto-notification to Slack/Discord |
cd your_flutter_app
flutter_distribute_manager
That's the whole workflow.
✅ What you'll need
| Requirement | What it's for | How to get it |
|---|---|---|
| Flutter & Dart (Dart ≥ 3.5) | Building the app | flutter.dev/get-started |
| rclone | Uploading to Google Drive | Installed for you by init |
| Xcode (macOS only) | Building iOS IPAs | Mac App Store, then xcode-select --install |
| Diawi token (optional) | iOS one-tap install links | diawi.com → Account → API |
You do not need a Google Cloud project, an OAuth client ID, or a service-account key. rclone signs you in through your browser.
📥 Install
dart pub global activate flutter_distribute_manager
Make sure the global bin directory is on your PATH (add to ~/.zshrc or ~/.bashrc):
export PATH="$PATH":"$HOME/.pub-cache/bin"
Verify:
flutter_distribute_manager --version
flutter_distribute_manager --help
⚡ Quick start (3 steps)
# 1️⃣ One-time setup — installs rclone, connects Google Drive, saves your Diawi token
flutter_distribute_manager init
# 2️⃣ Check everything is wired up correctly
flutter_distribute_manager doctor
# 3️⃣ From inside your Flutter project — build & ship
cd path/to/your/flutter_app
flutter_distribute_manager
That's it. The tool detects your project, asks for platform + environment, builds, uploads, and prints the share links.
🧭 Commands
| Command | What it does |
|---|---|
flutter_distribute_manager |
Build & ship (default, interactive). |
flutter_distribute_manager init |
One-time setup: rclone, Google Drive auth, Diawi token, webhook. |
flutter_distribute_manager doctor |
Health check: tools, config, Drive connectivity (+ macOS Gatekeeper). |
flutter_distribute_manager config |
View or edit saved configuration. |
flutter_distribute_manager reset |
Remove saved configuration and start over. |
🚩 Build flags
Every prompt has a flag, so any build is scriptable.
| Flag | Alias | Description |
|---|---|---|
--platform |
-p |
android, ios, or both. |
--app-dir |
-d |
Flutter project path (default: current dir). |
--app-name |
-n |
Label used in artifact file names. |
--environment |
-e |
DEV, UAT, or PROD. |
--team-id |
-t |
Apple Developer Team ID (iOS). |
--scheme |
Xcode scheme (default Runner). |
|
--flavor |
Build flavor passed through to flutter build. |
|
--flutter-path |
Explicit Flutter executable (overrides PATH/fvm detection). | |
--clean |
Run flutter clean before building. |
|
--export-method |
development, release-testing, or app-store. |
|
--diawi-token |
Diawi API token (overrides saved). | |
--upload-drive |
Upload artifacts to Google Drive. | |
--upload-diawi |
Upload the iOS IPA to Diawi. | |
--notify-url |
Slack / Discord / generic webhook to notify after a ship. | |
--retry |
Upload attempts before giving up (default 3). |
|
--[no-]split-per-abi |
Split Android APKs per ABI (default on). | |
--skip-build / --upload-only |
Reuse the last build instead of rebuilding. | |
--dry-run |
Print the plan without building or uploading. | |
--json |
Emit a machine-readable JSON result on stdout. | |
--yes |
-y |
Assume defaults; never prompt (CI/CD). |
--quiet |
-q |
Silence non-essential output (build chatter, detail lines). |
--verbose |
-v |
Verbose logging. |
--version |
Print version. |
🔄 Reset flags
reset clears saved configuration so you can start fresh.
| Flag | Alias | Description |
|---|---|---|
| (no flag) | Soft reset — deletes machine + project config. Drive stays connected. | |
--all |
Full reset — also deletes the rclone remote (disconnects Google Drive). | |
--app-dir |
-d |
Project whose config to remove (default: current dir). |
--yes |
-y |
Skip the confirmation prompt (for CI). |
# Clear settings but keep the Google Drive sign-in:
flutter_distribute_manager reset
# Wipe everything, including the Drive connection:
flutter_distribute_manager reset --all
Interactively, reset lists exactly what it will remove and asks you to type
reset to confirm — nothing is deleted by accident.
🤖 CI/CD example
Run fully non-interactive — perfect for GitHub Actions, GitLab CI, Codemagic, etc.:
flutter_distribute_manager \
--platform both \
--environment UAT \
--app-name MyApp \
--upload-drive \
--yes
Add --json to capture the result programmatically (all human output goes to
stderr, so stdout carries only clean JSON):
flutter_distribute_manager --platform android -e UAT --upload-drive --yes --json
🎬 A realistic end-to-end run
# Once, on your machine:
dart pub global activate flutter_distribute_manager
flutter_distribute_manager init # installs rclone, opens the browser to sign into Drive
flutter_distribute_manager doctor # ✔ Flutter ✔ rclone ✔ Google Drive reachable
# Every time you want QA to get the latest build:
cd ~/apps/acme
flutter_distribute_manager -p both -e UAT --upload-drive --upload-diawi --notify-url "$SLACK_HOOK" -y
# → builds APK + IPA
# → uploads APK to Drive: AcmeApp/2026/June/UAT/AcmeApp_UAT_2026_06_19_0930_arm64-v8a.apk
# → uploads IPA to Diawi and prints a one-tap install link
# → posts a summary to your Slack channel
🗂 How files land on Google Drive
Flutter Builds/
└── MyApp/
└── 2026/
└── June/
├── DEV/
├── UAT/
│ └── MyApp_UAT_2026_06_19_0930_arm64-v8a.apk
└── PROD/
Folder matching is case-insensitive, so re-runs reuse the same folders instead of piling up duplicates.
⚙️ Configuration
| Scope | Location | Stores |
|---|---|---|
| Machine | ~/.config/flutter_distribute_manager/config.json( %APPDATA%\flutter_distribute_manager\config.json on Windows) |
rclone remote, Drive folder, Diawi token, notify webhook. |
| Project | .flutter_distribute_manager.json in the project root |
last platform, app name, Team ID, scheme, export method, environment. |
The machine config holds API tokens, so on macOS/Linux it is written user-only (chmod 600).
🎯 fvm-pinned projects
If your app is pinned with fvm, you don't need a global flutter on your
PATH. The tool detects fvm (.fvmrc, .fvm/, or .fvm/fvm_config.json) and
runs the project's pinned SDK via fvm flutter … automatically — so builds use
the exact version your project expects.
doctorreportsFlutter (fvm 3.x.x) ✔when it resolves via fvm.- Override detection anytime with
--flutter-path /path/to/flutter.
🔢 Exit codes (for CI)
| Code | Meaning |
|---|---|
0 |
Success. |
64 |
Bad command-line usage. |
69 |
Upload failed (rclone / Diawi), or a build is already running. |
70 |
The build itself failed. |
78 |
Missing/invalid configuration (Flutter not found, Drive not set up). |
🛠 Troubleshooting
command not found: flutter_distribute_manager after installing
The global bin directory isn't on your PATH. Add it and reload your shell:
export PATH="$PATH":"$HOME/.pub-cache/bin" # add to ~/.zshrc or ~/.bashrc
source ~/.zshrc
macOS shows a security popup for flutter / dart / rclone (Gatekeeper)
Run flutter_distribute_manager doctor — it lists any quarantined binaries and
prints the exact xattr -d com.apple.quarantine <path> command to clear each one.
rclone remote … not found / Google Drive not reachable
Your sign-in expired or the remote was removed. Re-run:
flutter_distribute_manager init
# or, to just refresh the token:
rclone config reconnect <remote>:
iOS build fails immediately with an export-method error
Pass a value Flutter accepts: --export-method development (default),
release-testing, or app-store. For signed builds also pass --team-id.
"Xcode command-line tools" but the iOS build still can't archive
Command Line Tools alone aren't enough — install the full Xcode from the App
Store, then run xcode-select --install.
Noisy FINE: / SLVR: / IO : lines on the very first run
That's pub recompiling its snapshot right after dart pub global activate, not
this tool. It disappears on the next run. Use --quiet to trim build chatter,
or --json for clean machine-readable stdout.
A build "hangs" Almost always a signing prompt, an SDK licence question, or a CocoaPods/Gradle prompt waiting on input. Run once interactively to answer it; the tool closes child stdin and bounds output draining so daemons can't wedge the run.
❓ FAQ
Do I need a Google Cloud project or OAuth credentials?
No. rclone handles Google Drive sign-in in your browser during init.
Where is my Diawi token stored, and is it safe?
In the machine config file, written user-only (chmod 600) on macOS/Linux. It
is never echoed back to the terminal and is redacted from logs and errors.
Can I upload to Drive without rebuilding?
Yes — --skip-build (alias --upload-only) reuses the last build.
Does it work on Windows / Linux? Yes for Android builds and Drive uploads. iOS builds require macOS + Xcode.
How do I change a saved setting?
flutter_distribute_manager config (interactive), or override per-run with the
matching flag. To wipe everything, use reset (or reset --all to also
disconnect Drive).
Is this safe to run in CI?
Yes. Pass every value as a flag plus --yes for zero prompts, and --json for
a parseable result. Distinct exit codes (see above) let a pipeline react.
🧩 Programmatic use
The building blocks are also exported as a library:
import 'package:flutter_distribute_manager/flutter_distribute_manager.dart';
final project = FlutterProject.detect(Directory.current.path);
final artifacts = await AndroidBuilder(const ProcessRunner(), Logger())
.build(project!, environment: ReleaseEnvironment.uat);
See example/ for a full walkthrough.
📄 License
MIT © 2026 Ashutosh Tripathi. See LICENSE.
Libraries
- flutter_distribute_manager
- flutter_distribute_manager — a professional CLI that builds, packages and ships Flutter apps (Android APK / iOS IPA) to QA, with Google Drive uploads via rclone, Diawi install links and team notifications.