flutter_release_checker

pub package License: MIT

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

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, missing android: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.appiconset slots with no image assigned, and slots whose referenced file doesn't actually exist on disk (catching stale/broken Contents.json entries that would otherwise fail an Xcode archive)

Firebase

  • Config files: missing google-services.json / GoogleService-Info.plist when a firebase_* dependency is present

Supabase

  • Service role key: a hardcoded service_role JWT in lib/**/*.dart, which bypasses Row Level Security and must never ship in a client app. Detected by decoding the JWT payload's role claim, so the safe, public anon key is never flagged. Skipped when there's no supabase_flutter dependency.

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.dart from 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 version in pubspec.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.