Skip to content
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

Use new PlatformDispatcher onError method if available #109

Merged
merged 2 commits into from
Aug 2, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Use new PlatformDispatcher onError method if available
matux committed Aug 2, 2023
commit 1f5a4794a15f5899be05fcfdf2cab150aa13e99c
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart';

import 'package:rollbar_common/rollbar_common.dart';
import 'package:rollbar_dart/rollbar.dart';

import 'extension/diagnostics.dart';
import '../extension/diagnostics.dart';
import 'hook.dart';

extension RollbarFlutterError on FlutterError {
/// Called whenever the Flutter framework catches an error.
///
/// The default behavior is to call [presentError].
static void onError(FlutterErrorDetails error) {
@sealed
class FlutterHook implements Hook {
FlutterExceptionHandler? _originalOnError;

void onError(FlutterErrorDetails error) {
if (!error.silent) {
Rollbar.drop(
Breadcrumb.error(
@@ -27,6 +29,22 @@ extension RollbarFlutterError on FlutterError {
Rollbar.error(error.exception, error.stack ?? StackTrace.empty);
}

FlutterError.presentError(error);
if (_originalOnError != null) {
_originalOnError!(error);
}
}

@override
void install(_) {
_originalOnError = FlutterError.onError;
FlutterError.onError = onError;
}

@override
void uninstall() {
if (FlutterError.onError == onError) {
FlutterError.onError = _originalOnError;
_originalOnError = null;
}
}
}
9 changes: 9 additions & 0 deletions rollbar_flutter/lib/src/hooks/hook.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'dart:async';

import 'package:rollbar_dart/rollbar.dart';

abstract class Hook {
FutureOr<void> install(final Config config);

FutureOr<void> uninstall();
}
34 changes: 34 additions & 0 deletions rollbar_flutter/lib/src/hooks/platform_hook.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import 'dart:ui';
import 'package:rollbar_dart/rollbar.dart';
import 'hook.dart';

class PlatformHook implements Hook {
ErrorCallback? _originalOnError;
PlatformDispatcher? _platformDispatcher;

bool onError(Object exception, StackTrace stackTrace) {
Rollbar.error(exception, stackTrace);

if (_originalOnError != null) {
return _originalOnError!(exception, stackTrace);
}

return false;
}

@override
void install(_) {
_platformDispatcher = PlatformDispatcher.instance;
_originalOnError = _platformDispatcher?.onError;
_platformDispatcher?.onError = onError;
}

@override
void uninstall() {
if (_platformDispatcher?.onError == onError) {
_platformDispatcher?.onError = _originalOnError;
_originalOnError = null;
_platformDispatcher = null;
}
}
}
48 changes: 28 additions & 20 deletions rollbar_flutter/lib/src/rollbar.dart
Original file line number Diff line number Diff line change
@@ -7,7 +7,9 @@ import 'package:meta/meta.dart';

import 'package:rollbar_dart/rollbar.dart';

import 'flutter_error.dart';
import 'hooks/hook.dart';
import 'hooks/flutter_hook.dart';
import 'hooks/platform_hook.dart';
import 'platform_transformer.dart';

extension _Methods on MethodChannel {
@@ -22,48 +24,54 @@ extension _Methods on MethodChannel {
typedef RollbarClosure = FutureOr<void> Function();

@sealed
@immutable
class RollbarFlutter {
static const _platform = MethodChannel('com.rollbar.flutter');

RollbarFlutter._();
const RollbarFlutter._();

static Future<void> run(
Config config,
RollbarClosure appRunner,
) async {
if (!config.handleUncaughtErrors) {
WidgetsFlutterBinding.ensureInitialized();

await _run(config, appRunner, null);

return;
await _run(config, appRunner);
} else if (requiresCustomZone) {
await runZonedGuarded(
() async => await _run(config, appRunner, [FlutterHook()]),
Rollbar.error);
} else {
await _run(config, appRunner, [FlutterHook(), PlatformHook()]);
}

await runZonedGuarded(() async {
WidgetsFlutterBinding.ensureInitialized();

await _run(config, appRunner, RollbarFlutterError.onError);
}, (exception, stackTrace) {
Rollbar.error(exception, stackTrace);
});
}

static Future<void> _run(
Config config,
RollbarClosure appRunner,
FlutterExceptionHandler? onError,
) async {
RollbarClosure appRunner, [
List<Hook> hooks = const [],
]) async {
WidgetsFlutterBinding.ensureInitialized();

await Rollbar.run(config.copyWith(
framework: 'flutter',
persistencePath: await _platform.persistencePath,
transformer: (_) => PlatformTransformer(),
));

if (onError != null) {
FlutterError.onError = onError;
for (final hook in hooks) {
await hook.install(config);
}

await _platform.initialize(config: config);
await appRunner();
}

static bool get requiresCustomZone {
try {
(PlatformDispatcher.instance as dynamic)?.onError;
return false;
} on NoSuchMethodError {
return true;
}
}
}