ابرووا
شروع رایگان

اولین کرش فلاتر را ثبت و با نمادها بخوانید

در پایان: یک کرش آزمایشی در ابرووا تریس با استک‌تریس خوانا و مسیری که کاربر رفت.
ابرووا تریسFlutterمبتدی · ۲۰ دقیقه

پیش از شروع

اپ فلاترSDK ابرووا تریسمشکل در کنسول
این راهنما هنوز ترجمه نشده — نسخه‌ی انگلیسی نمایش داده می‌شود. English

In this guide you add Abrova Trace to a Flutter app, crash it on purpose, and read the result in Abrova Console: the stack trace, the screen the user was on and the button they tapped just before. The last step makes release builds just as readable on mobile and on the web.

Install the SDK from Abrova Center#

The package comes from Abrova Center, so you need no other package registry. Add it with the Abrova registry as its hosted source:

yaml
# pubspec.yaml
dependencies:
  abrova_trace_flutter_sdk:
    hosted: https://center.abrova.ir/api/packages/abrova/pub
    version: ^0.2.6

The plugin uses the native Android and iOS SDKs for native crash capture, so point those builds at Abrova too.

Android: add the Abrova Maven repository in android/build.gradle (or android/settings.gradle, wherever your project lists repositories):

groovy
allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url "https://center.abrova.ir/api/packages/abrova/maven" }
    }
}

iOS: add this inside the app target in ios/Podfile:

ruby
pod 'AbrovaTrace', :git => 'https://center.abrova.ir/abrova/abrova-trace-ios-sdk.git', :tag => '0.2.4'

Then install:

bash
flutter pub get

You need Dart 3.8.1 or newer, Android API 19 or newer, and iOS 12 or newer (built with Xcode 15.3+).

Initialise with your project key#

Copy the public key (ab_live_…) from Abrova Console → Project settings → Keys. It is safe inside an app. Never put the server secret (ab_srv_…) in an app.

Start Trace with initWithZone before WidgetsFlutterBinding.ensureInitialized(), and move the rest of your start-up into its callback. That way async errors are caught too.

dart
import 'package:flutter/material.dart';
import 'package:abrova_trace_flutter_sdk/abrova_trace_flutter_sdk.dart';

void main() async {
  await AbrovaTrace.initWithZone(
    AbrovaTraceConfig(
      apiKey: 'ab_live_your_api_key',
      release: '1.0.0', // match the version in pubspec.yaml
    ),
    () async {
      WidgetsFlutterBinding.ensureInitialized();

      // Every tap on a button becomes a breadcrumb.
      AbrovaTrace.enableGestureBreadcrumbs();

      runApp(const MyApp());
    },
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // Records screen changes as breadcrumbs and fills in the route of each tap.
      navigatorObservers: [AbrovaTraceNavigatorObserver()],
      home: const HomeScreen(),
    );
  }
}

release is how Trace pairs an error with the source maps and symbols you upload for that version (step 6). Use the same string everywhere, for example the version from pubspec.yaml.

Throw a test error#

Add a button that throws, and one that reports an error you caught yourself:

dart
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Trace test')),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            // Uncaught: Trace reports it on its own.
            ElevatedButton(
              key: const ValueKey('crash-button'),
              onPressed: () => throw StateError('Abrova test crash'),
              child: const Text('Crash'),
            ),
            // Caught: you report it, with extra data.
            ElevatedButton(
              onPressed: () async {
                try {
                  throw const FormatException('Abrova handled test');
                } catch (e, stackTrace) {
                  await AbrovaTrace.captureException(
                    e,
                    stackTrace: stackTrace,
                    extra: {'screen': 'HomeScreen'},
                  );
                }
              },
              child: const Text('Report a handled error'),
            ),
          ],
        ),
      ),
    );
  }
}

Run the app (flutter run) and tap both buttons. Always pass stackTrace when you report a caught error; without it the issue has no stack trace.

Read it in Abrova Console#

Open Abrova Console → Trace → Issues. Within a few seconds you see two issues: StateError: Abrova test crash and FormatException: Abrova handled test. Open the first one:

  • Stack trace: the frames of your own code, with .dart files and line numbers. The top frame is where the error happened.
  • Breadcrumbs: what happened before the error, ending with Tap on ElevatedButton: "Crash" and the route the user was on.
  • Context: device, OS and app version, and under Extra data anything you attached (screen on the second issue).
  • Release 1.0.0 and Environment production (the default).

Tap the button again: the event count of the same issue goes up instead of a new issue appearing, because repeats of one cause are grouped. Each event still counts toward your free 50,000 error events a month — grouping only keeps the list readable.

Native crashes come on the next launch#

Dart errors are sent as they happen. A native crash on Android or iOS (for example a crash inside a plugin's native code, or the system killing the app) ends the process before anything can be sent. The bundled native SDK writes the report to disk, and Trace sends it the next time the app starts. So after a native crash, open the app again, then look in Trace → Issues.

On the web, Dart errors, messages and logs work; native crash capture is Android and iOS only.

Make release builds readable#

What you need depends on the platform you ship:

BuildWhat to do
Android and iOS release (flutter build apk / appbundle / ipa)Nothing for Dart errors: method names and line numbers stay in the stack trace. Build without --obfuscate; Abrova Trace does not read the symbol files of --split-debug-info, so obfuscated Dart frames stay unreadable.
iOS native crashesUpload the dSYMs of the release in Abrova Console → Trace → Source maps & symbols → iOS dSYMs (a .zip, up to 10 MB).
Flutter webBuild with source maps and upload main.dart.js.map with the same release.

For Flutter web, build with source maps:

bash
flutter build web --source-maps --release

The map is at build/web/main.dart.js.map. Upload it in Abrova Console → Trace → Source maps & symbols (set the release to 1.0.0), or from CI with the Abrova Trace CLI (add the Abrova npm registry and install @abrova-trace/cli first, as that page shows):

bash
npx abrova-trace sourcemaps upload build/web --release "1.0.0"

Only errors captured after the upload are shown with your .dart files. In --release web builds the compiler inlines a lot, so some frames still point at framework files; the tap breadcrumbs from step 2 usually fill the gap. See Stack traces.

Troubleshooting#

Nothing shows up in Trace → Issues

Check that the key starts with ab_live_ and belongs to the project you are looking at, and that Abrova Trace is on for the project. Set debug: true in AbrovaTraceConfig to see the SDK's own log lines in the console while you test. Also check that the time range filter on the Issues page includes the last hour.

The async error is missing, the tap error is there

Use AbrovaTrace.initWithZone, and call WidgetsFlutterBinding.ensureInitialized() inside its callback, not before it. Errors from futures nobody awaits are only caught inside the zone.

A native crash never arrives

Native crashes are sent on the next launch: open the app again after the crash. Check that the Android Maven repository and the iOS pod line from step 1 are in place, and that you ran the app on a device or emulator, not on the web.

The web stack trace is still minified

The release you uploaded the map with must match the release in AbrovaTraceConfig exactly, and the error must happen after the upload. Check the release on the issue page and upload again with that exact string.

'Failed to initialize offline storage: Binding has not yet been initialized' at start

Versions before 0.2.6 can print this with initWithZone. It is harmless; update to 0.2.6, which no longer prints it.

Stack frames show short random names on Android or iOS

The build was made with --obfuscate. Build without it to get readable Dart frames in Trace.

دام‌ها
  • source map فلاتر وب و dSYM آی‌اواس فقط روی خطاهایی اعمال می‌شوند که همان نام ریلیزِ آپلود را دارند.
  • بیلدهایی که با ‎--obfuscate ساخته شوند خوانا نمی‌شوند: ابرووا تریس فایل‌های نماد Dart را نمی‌خواند.
  • کرش‌های نیتیو در اجرای بعدی اپ می‌رسند، نه همان لحظه.

بعدی: مرجع SDK فلاتر