flutter_release_checker
Audit your Flutter app before you ship it. Get a Production Ready Score, a readable terminal report, and a beautiful HTML report — right from your command line, or from your own Dart code.
Part of a small ecosystem of Flutter tooling:
| Package | Purpose |
|---|---|
flutter_architect |
Start your app |
flutter_release_checker |
Ship your app |
flutter_cache |
Manage your app's data |
Contents
- Install
- Usage
- CLI options
- What it checks (14 checks across 7 categories)
- The HTML report
- Programmatic API
- Roadmap
- Development
- Contributing
Install
dart pub global activate flutter_release_checker
(Or add it as a dev_dependency in your Flutter app and run it via dart run flutter_release_checker check.)
Usage
From the root of your Flutter project:
flutter_release_checker check
FLUTTER
⚠ Dart SDK Constraint
ANDROID
✖ Android Manifest
⚠ Permissions
⚠ SDK Versions
✖ Signing Config
⚠ App Icons
IOS
⚠ Info.plist
✖ Privacy Manifest
⚠ App Icons
...
──────────────────────────────────────────
Production Ready Score
🔴 0 / 100
──────────────────────────────────────────
Critical
❌ Debuggable flag enabled
❌ Release build uses debug signing config
❌ Missing Privacy Manifest
High
⚠ Cleartext traffic allowed
⚠ Components missing explicit android:exported
⚠ Sensitive permission: ACCESS_BACKGROUND_LOCATION
⚠ Target SDK version below Play Store requirement (30)
...
Recommendations
✔ Remove android:debuggable from the manifest and let Gradle set it per build type.
✔ Create a dedicated release signing config backed by your upload keystore...
──────────────────────────────────────────
HTML report written to build/release_report.html
Open build/release_report.html in your browser for a shareable, color-coded
report of the same results (see The HTML report).
CLI options
| Flag | Description |
|---|---|
--path, -p |
Path to the Flutter project root (default: .) |
--output, -o |
Where to write the HTML report (default: build/release_report.html) |
--html / --no-html |
Enable/disable the HTML report (default: on) |
--color / --no-color |
Enable/disable colored terminal output (default: on) |
--only |
Only run specific check ids, comma-separated (e.g. --only android_manifest,android_signing) |
--fail-under |
Exit with code 1 if the score is below this value — useful in CI |
What it checks — 14 checks across 7 categories
Flutter
- Dart SDK constraint: flags an outdated lower bound in
environment.sdk
Android
- Manifest:
debuggable, cleartext traffic, backup settings, missingandroid:exported - Permissions: sensitive/dangerous permissions requiring Play Console justification
- SDK versions: missing/outdated
compileSdk,minSdk,targetSdk - Signing: release build type falling back to debug signing, missing
key.properties - App icons: missing launcher icon densities, missing adaptive icon
iOS
Info.plist: missing version keys, disabled App Transport Security (NSAllowsArbitraryLoads)- Privacy Manifest: missing
PrivacyInfo.xcprivacy(required by Apple since 2024) - App icons:
AppIcon.appiconsetslots with no image assigned, and slots whose referenced file doesn't actually exist on disk (catching stale/brokenContents.jsonentries that would otherwise fail an Xcode archive)
Firebase
- Config files: missing
google-services.json/GoogleService-Info.plistwhen afirebase_*dependency is present
Supabase
- Service role key: a hardcoded
service_roleJWT inlib/**/*.dart, which bypasses Row Level Security and must never ship in a client app. Detected by decoding the JWT payload'sroleclaim, so the safe, publicanonkey is never flagged. Skipped when there's nosupabase_flutterdependency.
Security
- Hardcoded secrets: AWS/Google/Stripe/Slack/GitHub key patterns and private key blocks found in
lib/**/*.dart. Tool-generated files known to embed client-safe identifiers (e.g.firebase_options.dartfrom the FlutterFire CLI) are skipped to avoid false positives. - Insecure HTTP: plaintext
http://URLs hardcoded in Dart source
Store Readiness
- Version & build number: missing/malformed
versioninpubspec.yaml
Every check is skip-aware — e.g. iOS checks are skipped (not failed) when there's no ios/ directory, and Firebase/Supabase checks are skipped entirely if the project doesn't depend on them.
Note: checks verify configuration and file integrity (e.g. "does an icon file exist for every declared slot?"), not visual/design quality (e.g. "is this icon well-designed?" or "did you replace the default icon?"). They catch things that will break a build or a store submission, or that reviewers commonly flag — not subjective design choices.
The HTML report
build/release_report.html includes a circular score gauge, a one-line verdict
("Ready to ship" / "Needs work before release" / ...), severity-count pills,
a per-category pass/fail breakdown, a category-grouped checklist, and
issues tagged with both severity and category — all in a single
dependency-free dark-themed HTML file you can open straight in a browser or
attach to a PR.
Programmatic API
Everything the CLI does is also available as a library — see
example/ for a complete, runnable script:
import 'package:flutter_release_checker/flutter_release_checker.dart';
Future<void> main() async {
final project = FlutterProject.at('.');
final results = <CheckResult>[
for (final check in CheckRegistry.all) await check.run(project),
];
final score = const ScoreCalculator().calculate(results);
final report = ReleaseReport(
projectName: project.projectName,
results: results,
score: score,
generatedAt: DateTime.now(),
);
print(TerminalReporter().render(report));
const HtmlReporter().write(report, defaultHtmlReportPath(project.root.path));
}
Run it with:
dart run example/flutter_release_checker_example.dart path/to/your_flutter_app
Full API reference is generated via dartdoc from the doc comments on every
public class and member (see Development).
Roadmap
This CLI is the first of three planned surfaces for the same checks engine:
flutter_release_checker
├── CLI ← you are here
├── HTML Report ✔ already included
└── GitHub Action (planned: post the score as a PR comment)
Ideas for future checks, in no particular order: Universal Links/URL scheme validation, entitlements review, APK/IPA size and duplicate-asset detection, dependency/deprecated-package and security-advisory scanning, release notes and privacy-policy presence, screenshot validation, and detecting when an app still uses Flutter's default launcher icon.
Development
dart pub get
dart analyze # strict: public_member_api_docs is enforced
dart test # 45 tests across unit + integration coverage
dart doc . # generates API docs into doc/api/
dart pub publish --dry-run # validates packaging before a release
test/fixtures/sample_app is a deliberately-broken Flutter project (old
Dart SDK, missing build number, ATS disabled, missing privacy manifest,
missing Firebase config, a fake hardcoded AWS key, a fake Supabase
service_role key, an insecure HTTP call, etc.) used to exercise every
check end to end. Its fake credentials are allow-listed via false_secrets
in pubspec.yaml so they don't block publishing — see
dart.dev/go/false-secrets.
Contributing
Checks live in lib/src/checks/<category>/ (android/, ios/, firebase/,
security/, flutter/, store_readiness/) and implement the Check
interface (lib/src/checks/check.dart). Register new checks in
lib/src/checks/check_registry.dart — order there determines both terminal
grouping and category card order in the HTML report. See test/checks/ for
the expected test shape, and test/fixtures/ for sample projects to test
against.
Every public class and member should have a dartdoc comment
(public_member_api_docs is enforced by dart analyze).
License
MIT
Libraries
- flutter_release_checker
- Audit a Flutter app before you ship it.