Skip to content

Add multi-view troubleshooting guide for sentry dart #11308

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

Merged
merged 18 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7a14338
add multi-view troubleshooting guide for sentry dart
mar-hai Sep 10, 2024
c58f930
remove unused code
mar-hai Sep 10, 2024
407ad91
rephrase text and split up in general and example app related part.
mar-hai Sep 10, 2024
4b69eae
add complete example application instead of sentry example app adapta…
mar-hai Sep 30, 2024
b7f5dc3
Merge branch 'master' into martinhaintz/fix-flutter-multiview
mar-hai Oct 1, 2024
2c30ea8
Update docs/platforms/flutter/troubleshooting.mdx
martinhaintz Oct 1, 2024
7f7955b
Update docs/platforms/flutter/troubleshooting.mdx
martinhaintz Oct 1, 2024
a2d37be
Update includes/troubleshooting/flutter/enable_multi_view.mdx
martinhaintz Oct 16, 2024
6ac644e
Update docs/platforms/flutter/troubleshooting.mdx
martinhaintz Oct 16, 2024
e66ed2f
Update docs/platforms/flutter/troubleshooting.mdx
martinhaintz Oct 22, 2024
242ec96
Update docs/platforms/flutter/troubleshooting.mdx
martinhaintz Oct 22, 2024
91a443d
Update docs/platforms/flutter/troubleshooting.mdx
martinhaintz Oct 22, 2024
68f99a6
Update docs/platforms/flutter/troubleshooting.mdx
martinhaintz Oct 22, 2024
994c2be
Update includes/troubleshooting/flutter/enable_multi_view.mdx
martinhaintz Oct 22, 2024
7f0e3fe
update to match the latest PR
mar-hai Oct 22, 2024
97c512c
revert changes to previous commit.
mar-hai Oct 28, 2024
06c2123
Merge branch 'master' into martinhaintz/fix-flutter-multiview
mar-hai Nov 5, 2024
05f8102
Merge branch 'master' into martinhaintz/fix-flutter-multiview
mar-hai Nov 11, 2024
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
40 changes: 40 additions & 0 deletions docs/platforms/flutter/troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,43 @@ There is an [issue with the Sentry Flutter SDK](https://github.com/getsentry/sen
This is an [issue](https://github.com/flutter/flutter/issues/135245) with Flutter itself and should be fixed in [Flutter 3.15](https://github.com/flutter/flutter/labels/found%20in%20release%3A%203.15).

For prior versions, you can work around this by configuring the SDK only to take screenshots when the app is in the `resumed` state. To do this, set `SentryFlutterOptions.attachScreenshotOnlyWhenResumed` to `true`.

## Using Flutter Multi-view for Web

Multi-view embedding was introduced in Flutter 3.24. You'll find a detailed guide about it in the [Flutter docs](https://docs.flutter.dev/platform-integration/web/embedding-flutter-web) .

Using Sentry in a multi-view application is possible, but there are some limitations you should be aware of.
The following features don't currently support multi-view:

- Screenshots via the `SentryScreenshotWidget` (which is part of the `SentryWidget`)
- User interaction integration via the `SentryUserInteractionWidget` (which is part of the `SentryWidget`)
- Window and Device events via the `WidgetsBindingIntegration`

To prevent the `WidgetsBindingIntegration` from loading by default, you'll need to remove the integration as shown below:

```dart
// ignore: implementation_imports
import 'package:sentry_flutter/src/integrations/widgets_binding_integration.dart';
...
SentryFlutter.init(
(options) {
...
final integration = options.integrations
.firstWhere((element) => element is WidgetsBindingIntegration);
options.removeIntegration(integration);
},
// Init your App.
appRunner: appRunner,
);
```

### Example Application

Copy the `main.dart` file into the `lib` folder of your existing project. This file already contains the code of the `multi_view_app.dart` from the [`flutter documentation`](https://docs.flutter.dev/platform-integration/web/embedding-flutter-web#handling-view-changes-from-dart).
Next, copy the `flutter_bootstrap.js` file and the `index.html` file into the `web` folder.

Make sure you're using **Flutter 3.24** or newer and run the application.

Now you should be able to see **two** instances of the same application side by side, with different **ViewIds** in the `body`.

<Include name="troubleshooting/flutter/enable_multi_view.mdx" />
200 changes: 200 additions & 0 deletions includes/troubleshooting/flutter/enable_multi_view.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
```dart {filename:main.dart}{tabTitle: lib/main.dart}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:sentry_flutter/src/integrations/widgets_binding_integration.dart';
import 'dart:ui' show FlutterView;

const String exampleDsn = '___DSN___';

Future<void> main() async {
await SentryFlutter.init(
(options) {
options.dsn = exampleDsn;
final integration = options.integrations
.firstWhere((element) => element is WidgetsBindingIntegration);
options.removeIntegration(integration);
},
// Init your App.
appRunner: () => runWidget(
MultiViewApp(
viewBuilder: (BuildContext context) => DefaultAssetBundle(
bundle: SentryAssetBundle(),
child: const MyApp(),
),
),
),
);
}

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

@override
State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorObservers: [
SentryNavigatorObserver(),
],
home: Scaffold(
body: Center(
child: Text(
'Sentry Flutter Example (ViewId:${View.of(context).viewId})'),
),
),
);
}
}

// multi_view_app.dart

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/// Calls [viewBuilder] for every view added to the app to obtain the widget to
/// render into that view. The current view can be looked up with [View.of].
class MultiViewApp extends StatefulWidget {
const MultiViewApp({super.key, required this.viewBuilder});

final WidgetBuilder viewBuilder;

@override
State<MultiViewApp> createState() => _MultiViewAppState();
}

class _MultiViewAppState extends State<MultiViewApp>
with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_updateViews();
}

@override
void didUpdateWidget(MultiViewApp oldWidget) {
super.didUpdateWidget(oldWidget);
// Need to re-evaluate the viewBuilder callback for all views.
_views.clear();
_updateViews();
}

@override
void didChangeMetrics() {
_updateViews();
}

Map<Object, Widget> _views = <Object, Widget>{};

void _updateViews() {
final Map<Object, Widget> newViews = <Object, Widget>{};
for (final FlutterView view
in WidgetsBinding.instance.platformDispatcher.views) {
final Widget viewWidget = _views[view.viewId] ?? _createViewWidget(view);
newViews[view.viewId] = viewWidget;
}
setState(() {
_views = newViews;
});
}

Widget _createViewWidget(FlutterView view) {
return View(
view: view,
child: Builder(
builder: widget.viewBuilder,
),
);
}

@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

@override
Widget build(BuildContext context) {
return ViewCollection(views: _views.values.toList(growable: false));
}
}
```

```js {filename:flutter_bootstrap.js}{tabTitle: web/flutter_bootstrap.js}
// flutter_bootstrap.js
{{ flutter_js; }}
{{ flutter_build_config; }}

_flutter.loader.load({
onEntrypointLoaded: async function onEntrypointLoaded(engineInitializer) {
let engine = await engineInitializer.initializeEngine({
multiViewEnabled: true, // Enables embedded mode.
});
let app = await engine.runApp();
// Make this `app` object available to your JS app.
app.addView({ hostElement: document.querySelector("#left") });
app.addView({ hostElement: document.querySelector("#right") });
},
});
```

```html {filename:index.html}{tabTitle: web/index.html}
<!doctype html>
<html>
<head>
<!--
If you're serving your web app in a path other than the root, change the
href value below to reflect the base path you're serving from.

The path provided below has to start and end with a slash "/" in order for
it to work correctly.

For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF" />

<meta charset="UTF-8" />
<meta content="IE=Edge" http-equiv="X-UA-Compatible" />
<meta
name="description"
content="Demonstrates how to use the multiview feature with the sentry plugin."
/>

<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta
name="apple-mobile-web-app-title"
content="sentry multiview example"
/>
<link rel="apple-touch-icon" href="icons/Icon-192.png" />

<!-- Favicon -->
<link rel="shortcut icon" type="image/png" href="favicon.png" />

<title>sentry multiview example</title>
<link rel="manifest" href="manifest.json" />
</head>
<body>
<div style="width: 100%; height: 100%; position: absolute;">
<div id="left" style="width: 50%; height: 100%; float: left;"></div>
<div id="right" style="width: 50%; height: 100%; float: left;"></div>
</div>
<script
src="flutter_bootstrap.js"
type="application/javascript"
async
></script>
</body>
</html>
```
Loading