diff --git a/CHANGELOG.md b/CHANGELOG.md index 2474c7e423..d878c77b19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ - Prefix firebase remote config feature flags with `firebase:` ([#3258](https://github.com/getsentry/sentry-dart/pull/3258)) +### Fixes + +- Safely access browser `navigator.deviceMemory` ([#3268](https://github.com/getsentry/sentry-dart/pull/3268)) + ## 9.7.0-beta.5 ### Dependencies diff --git a/packages/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart b/packages/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart index e1a73612d2..f5efff0391 100644 --- a/packages/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart +++ b/packages/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart @@ -1,4 +1,5 @@ import 'package:web/web.dart' as web show window, Window, Navigator; +import 'dart:js_interop'; import '../../../sentry.dart'; import 'enricher_event_processor.dart'; @@ -69,8 +70,7 @@ class WebEnricherEventProcessor implements EnricherEventProcessor { int? _getMemorySize() { // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/deviceMemory - // ignore: invalid_null_aware_operator - final size = _window.navigator.deviceMemory?.toDouble(); + final size = _window.navigator.safeDeviceMemory?.toDouble(); final memoryByteSize = size != null ? size * 1024 * 1024 * 1024 : null; return memoryByteSize?.toInt(); } @@ -116,7 +116,15 @@ class WebEnricherEventProcessor implements EnricherEventProcessor { } } -extension on web.Navigator { - // ignore: unused_element - external double? get deviceMemory; +/// Some Navigator properties are not fully supported in all browsers. +/// However, package:web does not provide a safe way to access these properties, +/// and assumes they are always not null. +/// +/// This extension provides a safe way to access these properties. +/// +/// See: https://github.com/dart-lang/web/issues/326 +/// https://github.com/fluttercommunity/plus_plugins/issues/3391 +extension SafeNavigationGetterExtensions on web.Navigator { + @JS('deviceMemory') + external double? get safeDeviceMemory; } diff --git a/packages/dart/test/event_processor/enricher/web_enricher_test.dart b/packages/dart/test/event_processor/enricher/web_enricher_test.dart index 1c3639ec42..6f2d35cad1 100644 --- a/packages/dart/test/event_processor/enricher/web_enricher_test.dart +++ b/packages/dart/test/event_processor/enricher/web_enricher_test.dart @@ -5,6 +5,7 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/event_processor/enricher/web_enricher_event_processor.dart'; import 'package:sentry/src/platform/mock_platform.dart'; import 'package:test/test.dart'; +import 'package:web/web.dart' as web; import '../../mocks.dart'; import '../../test_utils.dart'; @@ -195,6 +196,18 @@ void main() { expect(sentryOptions.eventProcessors.map((e) => e.runtimeType.toString()), contains('$WebEnricherEventProcessor')); }); + + test('SafeNavigationGetterExtensions safely accesses deviceMemory', () { + // Test that the extension can safely access deviceMemory without throwing + final navigator = web.window.navigator; + + // This should not throw an exception even if deviceMemory is not supported + final deviceMemory = navigator.safeDeviceMemory; + + // deviceMemory can be null if not supported by the browser + // or a double value if supported + expect(deviceMemory == null || deviceMemory > 0, isTrue); + }); }); }