Skip to content

feat: update cr setup #598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: dev
Choose a base branch
from
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.1) (Jul 7, 2025)
## [Unreleased](https://github.com/Instabug/Instabug-Flutter/compare/v15.0.1...dev)

### Added

- Added `InstabugWidget`, a wrapper used to wrap the main application to provide out of the box automatic Crash Reporting support. ([#598](https://github.com/Instabug/Instabug-Flutter/pull/598))

## [15.0.2](https://github.com/Instabug/Instabug-Flutter/compare/v14.3.0...15.0.1)

### Added

Expand Down
30 changes: 13 additions & 17 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:instabug_flutter/instabug_flutter.dart';
import 'package:instabug_flutter/src/utils/instabug_widget.dart';
import 'package:instabug_flutter_example/src/components/apm_switch.dart';
import 'package:instabug_http_client/instabug_http_client.dart';
import 'package:instabug_flutter_example/src/app_routes.dart';
Expand Down Expand Up @@ -43,24 +44,19 @@ part 'src/components/traces_content.dart';
part 'src/components/flows_content.dart';

void main() {
runZonedGuarded(
() {
WidgetsFlutterBinding.ensureInitialized();

Instabug.init(
token: 'ed6f659591566da19b67857e1b9d40ab',
invocationEvents: [InvocationEvent.floatingButton],
debugLogsLevel: LogLevel.verbose,
);

FlutterError.onError = (FlutterErrorDetails details) {
Zone.current.handleUncaughtError(details.exception, details.stack!);
};

runApp(const MyApp());
},
CrashReporting.reportCrash,
WidgetsFlutterBinding.ensureInitialized();

Instabug.init(
token: 'ed6f659591566da19b67857e1b9d40ab',
invocationEvents: [InvocationEvent.floatingButton],
debugLogsLevel: LogLevel.verbose,
);

final app = InstabugWidget(
child: const MyApp(),
);

runApp(app);
}

class MyApp extends StatelessWidget {
Expand Down
4 changes: 4 additions & 0 deletions example/lib/src/components/non_fatal_crashes_content.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class _NonFatalCrashesContentState extends State<NonFatalCrashesContent> {
log('throwHandledException: Crash report for ${err.runtimeType} is Sent!',
name: 'NonFatalCrashesWidget');
}
CrashReporting.reportHandledCrash(
err,
StackTrace.current,
);
}
}

Expand Down
147 changes: 147 additions & 0 deletions lib/src/utils/instabug_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:instabug_flutter/src/modules/crash_reporting.dart';
import 'package:instabug_flutter/src/utils/instabug_logger.dart';

class InstabugWidget extends StatefulWidget {
final Widget child;

/// Custom handler for Flutter errors.
///
/// This callback is called when a Flutter error occurs. It receives a
/// [FlutterErrorDetails] object containing information about the error.
///
/// Example:
/// ```dart
/// InstabugWidget(
/// flutterErrorHandler: (details) {
/// print('Flutter error: ${details.exception}');
/// // Custom error handling logic
/// },
/// child: MyApp(),
/// )
/// ```
///
/// Note: If this handler throws an error, it will be caught and logged
/// to prevent it from interfering with Instabug's error reporting.
final Function(FlutterErrorDetails)? flutterErrorHandler;

/// Custom handler for platform errors.
///
/// This callback is called when a platform error occurs. It receives the
/// error object and stack trace.
///
/// Example:
/// ```dart
/// InstabugWidget(
/// platformErrorHandler: (error, stack) {
/// print('Platform error: $error');
/// // Custom error handling logic
/// },
/// child: MyApp(),
/// )
/// ```
///
/// Note: If this handler throws an error, it will be caught and logged
/// to prevent it from interfering with Instabug's error reporting.
final Function(Object, StackTrace)? platformErrorHandler;

/// Whether to handle Flutter errors.
///
/// If true, the Flutter error will be reported as a non-fatal crash, instead of a fatal crash.
final bool nonFatalFlutterErrors;

/// The level of the non-fatal exception.
///
/// This is used to determine the level of the non-fatal exception.
///
/// Note: This has no effect if [nonFatalFlutterErrors] is false.
final NonFatalExceptionLevel nonFatalExceptionLevel;

/// This widget is used to wrap the root of your application. It will automatically
/// configure both FlutterError.onError and PlatformDispatcher.instance.onError handlers to report errors to Instabug.
///
/// Example:
/// ```dart
/// MaterialApp(
/// home: InstabugWidget(
/// child: MyApp(),
/// ),
/// )
/// ```
///
/// Note: Custom error handlers are called before the error is reported to Instabug.
const InstabugWidget({
Key? key,
required this.child,
this.flutterErrorHandler,
this.platformErrorHandler,
this.nonFatalFlutterErrors = false,
this.nonFatalExceptionLevel = NonFatalExceptionLevel.error,
}) : super(key: key);

@override
State<InstabugWidget> createState() => _InstabugWidgetState();
}

class _InstabugWidgetState extends State<InstabugWidget> {
@override
void initState() {
super.initState();
_setupErrorHandlers();
}

void _setupErrorHandlers() {
FlutterError.onError = (FlutterErrorDetails details) {
// Call user's custom handler if provided
if (widget.flutterErrorHandler != null) {
try {
widget.flutterErrorHandler!(details);
} catch (e) {
InstabugLogger.I.e(
'Custom Flutter error handler failed: $e',
tag: 'InstabugWidget',
);
}
}

if (widget.nonFatalFlutterErrors) {
CrashReporting.reportHandledCrash(
details.exception,
details.stack ?? StackTrace.current,
level: widget.nonFatalExceptionLevel,
);
} else {
CrashReporting.reportCrash(
details.exception,
details.stack ?? StackTrace.current,
);
}

FlutterError.presentError(details);
};

PlatformDispatcher.instance.onError = (Object error, StackTrace stack) {
// Call user's custom handler if provided
if (widget.platformErrorHandler != null) {
try {
widget.platformErrorHandler!(error, stack);
} catch (e) {
InstabugLogger.I.e(
'Custom platform error handler failed: $e',
tag: 'InstabugWidget',
);
}
}

CrashReporting.reportCrash(error, stack);

return true;
};
}

@override
Widget build(BuildContext context) {
return widget.child;
}
}