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

Fix: Use PlatformDispatcher.onError in Flutter 3.3 #1039

Merged
merged 26 commits into from
Oct 13, 2022
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
60fba54
dont call apprunner in runzonedguarded if onError is supported
denrase Oct 3, 2022
df7b25d
Merge branch 'main' into fix/platform-dispatcher-onerror
denrase Oct 3, 2022
a18c5ac
format
denrase Oct 3, 2022
9360251
update changelog
denrase Oct 3, 2022
1a43cf1
fix analyze issues
denrase Oct 3, 2022
34a2d4f
use BindingUtils.getWidgetsBindingInstance() to access platform dispa…
denrase Oct 3, 2022
412aa83
dont check if error is supported again
denrase Oct 3, 2022
7d6f830
mark callAppRunnerInRunZonedGuarded as internal
denrase Oct 3, 2022
9b69409
Merge branch 'main' into fix/platform-dispatcher-onerror
denrase Oct 10, 2022
f3e8676
use PlatformDispatcher.instance
denrase Oct 10, 2022
628880b
move changelog entry to features
denrase Oct 10, 2022
3e52249
use type inference
denrase Oct 11, 2022
1c792b6
ignore warning
denrase Oct 11, 2022
315be14
remove unused import
denrase Oct 11, 2022
8189aaf
recreate mock.mocks.dart
denrase Oct 11, 2022
7b9e707
Merge branch 'main' into fix/platform-dispatcher-onerror
denrase Oct 11, 2022
281547a
Merge branch 'main' into fix/platform-dispatcher-onerror
marandaneto Oct 11, 2022
609026b
fix incorrect changelog
denrase Oct 11, 2022
f27e3c2
Merge branch 'main' into fix/platform-dispatcher-onerror
marandaneto Oct 11, 2022
a4d6e42
add WidgetsFlutterBindingIntegration before OnErrorIntegration
denrase Oct 11, 2022
6fdd196
Merge branch 'main' into fix/platform-dispatcher-onerror
denrase Oct 11, 2022
4ea91c6
add newline
denrase Oct 11, 2022
001e443
test that WidgetsFlutterBindingIntegration is before OnErrorIntegration
denrase Oct 11, 2022
33ad3ec
Merge branch 'main' into fix/platform-dispatcher-onerror
marandaneto Oct 13, 2022
485b071
fix
marandaneto Oct 13, 2022
1c94f1e
Merge branch 'main' into fix/platform-dispatcher-onerror
marandaneto Oct 13, 2022
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Features

- Use PlatformDispatcher.onError in Flutter 3.3 ([#1039](https://github.com/getsentry/sentry-dart/pull/1039))

### Fixes

- Bring protocol up to date with latest Sentry protocol ([#1038](https://github.com/getsentry/sentry-dart/pull/1038))
Expand Down
42 changes: 26 additions & 16 deletions dart/lib/src/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class Sentry {
static Future<void> init(
OptionsConfiguration optionsConfiguration, {
AppRunner? appRunner,
@internal bool callAppRunnerInRunZonedGuarded = true,
@internal SentryOptions? options,
}) async {
final sentryOptions = options ?? SentryOptions();
Expand All @@ -56,7 +57,7 @@ class Sentry {
throw ArgumentError('DSN is required.');
}

await _init(sentryOptions, appRunner);
await _init(sentryOptions, appRunner, callAppRunnerInRunZonedGuarded);
}

static Future<void> _initDefaultValues(
Expand Down Expand Up @@ -96,7 +97,11 @@ class Sentry {
}

/// Initializes the SDK
static Future<void> _init(SentryOptions options, AppRunner? appRunner) async {
static Future<void> _init(
SentryOptions options,
AppRunner? appRunner,
bool callAppRunnerInRunZonedGuarded,
) async {
if (isEnabled) {
options.logger(
SentryLevel.warning,
Expand All @@ -113,21 +118,26 @@ class Sentry {

// execute integrations after hub being enabled
if (appRunner != null) {
var runIntegrationsAndAppRunner = () async {
final integrations =
options.integrations.where((i) => i is! RunZonedGuardedIntegration);
await _callIntegrations(integrations, options);
if (callAppRunnerInRunZonedGuarded) {
var runIntegrationsAndAppRunner = () async {
final integrations = options.integrations
.where((i) => i is! RunZonedGuardedIntegration);
await _callIntegrations(integrations, options);
await appRunner();
};

final runZonedGuardedIntegration =
RunZonedGuardedIntegration(runIntegrationsAndAppRunner);
options.addIntegrationByIndex(0, runZonedGuardedIntegration);

// RunZonedGuardedIntegration will run other integrations and appRunner
// runZonedGuarded so all exception caught in the error handler are
// handled
await runZonedGuardedIntegration(HubAdapter(), options);
} else {
await _callIntegrations(options.integrations, options);
await appRunner();
};

final runZonedGuardedIntegration =
RunZonedGuardedIntegration(runIntegrationsAndAppRunner);
options.addIntegrationByIndex(0, runZonedGuardedIntegration);

// RunZonedGuardedIntegration will run other integrations and appRunner
// runZonedGuarded so all exception caught in the error handler are
// handled
await runZonedGuardedIntegration(HubAdapter(), options);
}
} else {
await _callIntegrations(options.integrations, options);
}
Expand Down
25 changes: 25 additions & 0 deletions dart/test/sentry_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,31 @@ void main() {
});
});

test('should complete when appRunner is not called in runZonedGuarded',
() async {
final completer = Completer();
var completed = false;

final init = Sentry.init(
(options) {
options.dsn = fakeDsn;
},
appRunner: () => completer.future,
callAppRunnerInRunZonedGuarded: false,
).whenComplete(() => completed = true);

await Future(() {
// We make the expectation only after all microtasks have completed,
// that Sentry.init might have scheduled.
expect(completed, false);
});

completer.complete();
await init;

expect(completed, true);
});

test('options.environment debug', () async {
final sentryOptions = SentryOptions(dsn: fakeDsn)
..platformChecker = FakePlatformChecker.debugMode();
Expand Down
14 changes: 0 additions & 14 deletions flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -187,20 +187,6 @@ class MainScaffold extends StatelessWidget {
},
child: const Text('Capture from FlutterError.onError'),
),
ElevatedButton(
onPressed: () {
// Only usable on Flutter >= 3.3
// and needs the following additional setup:
// options.addIntegration(OnErrorIntegration());
(WidgetsBinding.instance.platformDispatcher as dynamic)
.onError
?.call(
Exception('PlatformDispatcher.onError'),
StackTrace.current,
);
},
child: const Text('Capture from PlatformDispatcher.onError'),
),
ElevatedButton(
onPressed: () => makeWebRequest(context),
child: const Text('Dart: Web request'),
Expand Down
2 changes: 1 addition & 1 deletion flutter/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ dependencies:

dev_dependencies:
pedantic: ^1.11.1
sentry_dart_plugin: ^1.0.0-alpha.4
sentry_dart_plugin: ^1.0.0-beta.1

dependency_overrides:
sentry:
Expand Down
4 changes: 0 additions & 4 deletions flutter/lib/src/integrations/on_error_integration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@ class OnErrorIntegration implements Integration<SentryFlutterOptions> {
// WidgetsBinding works with WidgetsFlutterBinding and other custom bindings
final wrapper = dispatchWrapper ??
PlatformDispatcherWrapper(binding.platformDispatcher);

if (!wrapper.isOnErrorSupported(options)) {
return;
}
_defaultOnError = wrapper.onError;

_integrationOnError = (Object exception, StackTrace stackTrace) {
Expand Down
18 changes: 15 additions & 3 deletions flutter/lib/src/sentry_flutter.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import 'dart:async';
import 'dart:ui';

import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:sentry/sentry.dart';
import '../sentry_flutter.dart';
import 'event_processor/android_platform_exception_event_processor.dart';
import 'native_scope_observer.dart';
import 'sentry_native.dart';
Expand All @@ -13,9 +14,7 @@ import 'sentry_native_channel.dart';
import 'event_processor/flutter_enricher_event_processor.dart';
import 'integrations/debug_print_integration.dart';
import 'integrations/native_app_start_integration.dart';
import 'sentry_flutter_options.dart';

import 'default_integrations.dart';
import 'file_system_transport.dart';

import 'version.dart';
Expand Down Expand Up @@ -45,12 +44,17 @@ mixin SentryFlutter {
final native = SentryNative();
native.setNativeChannel(nativeChannel);

final platformDispatcher = PlatformDispatcher.instance;
final wrapper = PlatformDispatcherWrapper(platformDispatcher);
final isOnErrorSupported = wrapper.isOnErrorSupported(flutterOptions);
denrase marked this conversation as resolved.
Show resolved Hide resolved

// first step is to install the native integration and set default values,
// so we are able to capture future errors.
final defaultIntegrations = _createDefaultIntegrations(
packageLoader,
channel,
flutterOptions,
isOnErrorSupported,
);
for (final defaultIntegration in defaultIntegrations) {
flutterOptions.addIntegration(defaultIntegration);
Expand All @@ -65,6 +69,8 @@ mixin SentryFlutter {
appRunner: appRunner,
// ignore: invalid_use_of_internal_member
options: flutterOptions,
// ignore: invalid_use_of_internal_member
callAppRunnerInRunZonedGuarded: !isOnErrorSupported,
);
}

Expand Down Expand Up @@ -96,6 +102,7 @@ mixin SentryFlutter {
PackageLoader packageLoader,
MethodChannel channel,
SentryFlutterOptions options,
bool isOnErrorSupported,
) {
final integrations = <Integration>[];
final platformChecker = options.platformChecker;
Expand All @@ -104,6 +111,11 @@ mixin SentryFlutter {
// Will call WidgetsFlutterBinding.ensureInitialized() before all other integrations.
integrations.add(WidgetsFlutterBindingIntegration());

// Use PlatformDispatcher.onError instead of zones.
if (isOnErrorSupported) {
integrations.add(OnErrorIntegration());
}

// Will catch any errors that may occur in the Flutter framework itself.
integrations.add(FlutterErrorIntegration());

Expand Down
2 changes: 1 addition & 1 deletion flutter/test/mocks.mocks.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Mocks generated by Mockito 5.3.1 from annotations
// Mocks generated by Mockito 5.3.2 from annotations
// in sentry_flutter/example/windows/flutter/ephemeral/.plugin_symlinks/sentry_flutter/example/linux/flutter/ephemeral/.plugin_symlinks/sentry_flutter/example/ios/.symlinks/plugins/sentry_flutter/test/mocks.dart.
// Do not manually edit this file.

Expand Down
Loading