crash_reporting (1.0.0)

Published 2026-10-02 15:58:06 +00:00 by Platform

Installation

dart pub add crash_reporting:1.0.0 --hosted-url=

About this package

Crash reporting for Flutter apps: Dart errors, Android native deaths (exit reasons, decoded tombstones), device context and the recent log, posted as JSON to the app's own backend.

Dart.Package.CrashReporting

Crash reporting for Flutter apps, published as crash_reporting on the Platform pub feed. Reports go to the app's own backend as JSON; there is no third-party service.

What it catches:

  • Dart errors: framework errors (FlutterError.onError), unhandled async errors (PlatformDispatcher.onError) and whatever the app's runZonedGuarded sees. An image that fails to load for a network reason is a log warning, not a report.
  • Android process deaths Dart never sees (native crash, GPU driver, WebView, ANR, out of memory, Java crash), reported on the next launch from ActivityManager.getHistoricalProcessExitReasons (API 30+). The first check looks back a week; later checks start where the last one stopped.
    • A native tombstone is decoded from protobuf into debuggerd's text form: the crashing thread's backtrace first (rel pc, library, BuildId), then the logcat lines Android kept, then six frames of every other thread, so the 60,000-character cap cuts the least useful part.
    • Android keeps no trace for a Java crash, so the plugin writes the uncaught exception to files/last_java_crash.txt and attaches it to an exit within a minute of it.
    • A crash on the WebView's in-process GPU thread (Chrome_InProcGp in a GPU driver library) is flagged webViewGpuCrash: true in the exit, so an app can turn its WebView feature off on the next launch.

Each report carries the device, OS, screen, route, lifecycle, memory, build mode, a settings snapshot without anything named like a token or secret, and the last 400 log lines. Emails and token-like strings are scrubbed; BuildId: and build_id: hex is kept because symbolizing needs it. Reports are on by default; the user's choice and a random install id (a dashed Guid) are kept in a store the app provides.

Wiring it into an app

Future<void> main() async {
  late final CrashReporter crashReporter;

  runZonedGuarded(
    () async {
      WidgetsFlutterBinding.ensureInitialized();
      final store = await openMyKeyValueStore('crash_reporting.json');

      crashReporter = CrashReporter(
        api: HttpCrashReportApi(client: http.Client(), baseUrl: Uri.parse(apiBaseUrl)),
        store: (read: store.read, write: store.write),
        appVersion: appVersion,
        platform: platformName,
        facts: CrashContext.facts(appVersion: appVersion, earlierLog: readLogFile),
      );
      await crashReporter.initialize();
      unawaited(CrashContext.loadDevice().then((_) => crashReporter.reportNativeExits()));
      reportUncaughtErrors(crashReporter, logError: log.error, logWarning: log.warning);

      runApp(const MyApp());
    },
    (error, stack) => crashReporter.reportError(error, stack, kind: 'zone'),
  );
}

Feed the context as the app runs:

  • CrashContext.addLine(line) from the app's logger, already scrubbed of anything app-specific.
  • CrashContext.route from a NavigatorObserver, CrashContext.lifecycle from a WidgetsBindingObserver.
  • CrashContext.useSettings(settings.toJson()) whenever settings change.

crashReporter.setEnabled(bool) backs the user's switch in settings.

The backend contract

POST {baseUrl}/errors (HttpCrashReportApi.path to change it), anonymous, application/json:

Field
message, stackTrace Scrubbed. A native exit's stackTrace is the decoded tombstone or Java trace
appVersion, platform, installId installId is a dashed Guid
occurredAt UTC ISO 8601; for a native exit, when the process died
kind flutter, unhandled, zone, or an Android exit reason: crash-native, crash-java, anr, init-failure, excessive-resources, low-memory, signaled
context Optional JSON string: the device facts above, plus exit and reportedLater for a native exit
log Optional: the last 60,000 characters of the log, cut from the front

Any status of 400 or above counts as a failure; failures are swallowed so reporting never throws into the app. Service.Pedalsim.Backend's ErrorsController is a working receiver.

Testing

flutter test runs the Dart tests. The Kotlin tests (android/src/test) need an Android SDK, which CI lacks; run them from any app that depends on the package:

android/gradlew -p android :crash_reporting:testDebugUnitTest

Publishing

Bump Version.txt and push to main; flutter-publish publishes it when that version is not on the feed yet.

Details
Pub
2026-10-02 15:58:06 +00:00
247
18 KiB
Assets (1)
1.0.0.tar.gz 18 KiB
Versions (3) View all
1.2.0 2026-10-26
1.1.0 2026-10-24
1.0.0 2026-10-02