Flutter崩溃报告与错误追踪插件bugsee_flutter的使用

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter崩溃报告与错误追踪插件bugsee_flutter的使用

Bugsee for Flutter

Bugsee 是一个移动SDK,可以为您的错误和崩溃报告添加关键信息。Bugsee 报告包括用户操作的视频、网络流量、控制台日志和其他重要跟踪信息。现在您可以确切地知道是什么导致了意外行为。

注册服务请访问 Bugsee 官网

安装

pubspec.yaml 文件中添加 Bugsee 插件依赖:

dependencies:
  bugsee_flutter: ^8.4.2

启动

在主函数中启动 Bugsee,并配置应用运行回调:

import 'package:bugsee_flutter/bugsee_flutter.dart';
import 'dart:io';
import 'package:flutter/material.dart';

Future<void> launchBugsee(void Function(bool isBugseeLaunched) appRunner) async {
  var launchOptions;
  var bugseeToken = "";

  if (Platform.isAndroid) {
    bugseeToken = "<android app token>";
    launchOptions = AndroidLaunchOptions();
  } else if (Platform.isIOS) {
    bugseeToken = "<ios app token>";
    launchOptions = IOSLaunchOptions();
  }

  await Bugsee.launch(bugseeToken,
      appRunCallback: appRunner, launchOptions: launchOptions);
}

Future<void> main() async {
  // 这是为了让 Bugsee 拦截网络请求
  HttpOverrides.global = Bugsee.defaultHttpOverrides;

  await launchBugsee((bool isBugseeLaunched) async {
    runApp(const MyApp());
  });
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;

  MyHomePage({required this.title});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              child: Text('Dart exception'),
              onPressed: () {
                throw StateError('This is a Dart exception.');
              },
            ),
            ElevatedButton(
              child: Text('async Dart exception'),
              onPressed: () async {
                foo() async {
                  throw StateError('This is an async Dart exception.');
                }

                bar() async {
                  await foo();
                }

                await bar();
              },
            ),
            ElevatedButton(
              child: Text('Java exception'),
              onPressed: () async {
                Bugsee.testExceptionCrash();
              },
            ),
            ElevatedButton(
              child: Text('Handled exception'),
              onPressed: () async {
                try {
                  throw FormatException('Expected at least 1 section');
                } catch (ex, st) {
                  Bugsee.logException(ex, st);
                }
              },
            ),
            ElevatedButton(
              child: Text('Handled empty exception'),
              onPressed: () {
                Bugsee.logException(
                    StateError('This is a Dart exception with empty stack trace.'),
                    '');
              },
            ),
            ElevatedButton(
              child: Text('Exception in another isolate'),
              onPressed: () async {
                Isolate isolate = await Isolate.spawn((dynamic arg) {
                  throw StateError('This is an exception in another isolate.');
                }, "", paused: true, errorsAreFatal: false);
                isolate.addBugseeErrorListener();
                if (isolate.pauseCapability != null) {
                  isolate.resume(isolate.pauseCapability!);
                }
              },
            ),
            ElevatedButton(
              child: Text('Log messages'),
              onPressed: () {
                print("This is a message posted with print() call");
                Bugsee.log("This is a test console message");
                Bugsee.log("This is a test console ERROR message", BugseeLogLevel.error);
                Bugsee.log("This is a test console DEBUG message", BugseeLogLevel.debug);
                Bugsee.log("This is a test console INFO message", BugseeLogLevel.info);
                Bugsee.log("This is a test console WARNING message", BugseeLogLevel.warning);
              },
            ),
            ElevatedButton(
              child: Text('Network request'),
              onPressed: () async {
                var response = await http.post(
                  Uri.parse('https://reqres.in/api/users'),
                  headers: <String, String>{
                    'Content-Type': 'application/json; charset=UTF-8',
                  },
                  body: jsonEncode(<String, String>{
                    'title': 'Some fancy title',
                  }),
                );
                var responseBody = response.body;
                print('Received network response. Length: ${responseBody.length}');
              },
            ),
            ElevatedButton(
              child: Text('Custom events'),
              onPressed: () async {
                Map<String, dynamic> params = <String, dynamic>{};
                params['string'] = 'test';
                params['int'] = 5;
                params['float'] = 0.55;
                params['bool'] = true;
                Bugsee.event('event', params);
                Bugsee.trace('number', 5);
                Bugsee.trace('float', 0.55);
                Bugsee.trace('string', 'test');
                Bugsee.trace('bool', true);
                Bugsee.trace('map', params);
                Bugsee.setAttribute('age', 36);
                Bugsee.setAttribute('name', 'John Doe');
                Bugsee.setAttribute('married', false);
              },
            ),
            ElevatedButton(
              child: Text('Show report dialog'),
              onPressed: () {
                Bugsee.showReportDialog('Test summary', 'Test description');
              },
            ),
            ElevatedButton(
              child: Text('Upload report'),
              onPressed: () {
                Bugsee.upload('Test summary', 'Test description');
              },
            ),
            ElevatedButton(
              child: Text('Show Feedback'),
              onPressed: () {
                Bugsee.showFeedbackUI();
              },
            ),
            ElevatedButton(
              child: Text('Add secure rect'),
              onPressed: () {
                Bugsee.addSecureRect(Rectangle(20, 20, 100, 100));
              },
            ),
            ElevatedButton(
              child: Text('Get all secure rects'),
              onPressed: () async {
                dynamic rects = await Bugsee.getAllSecureRects();
                print(rects);
              },
            ),
            ElevatedButton(
              child: Text('Capture view hierarchy'),
              onPressed: () async {
                await Bugsee.captureViewHierarchy();
              },
            ),
            ElevatedButton(
              child: Text('Show video'),
              onPressed: () async {
                showDialog(
                    context: context,
                    builder: (BuildContext context) => _buildVideoPopupDialog(context));
              },
            ),
            ElevatedButton(
              child: Text('Dummy button'),
              onPressed: () async {},
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildVideoPopupDialog(BuildContext context) {
    return Dialog(
        child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(children: [
              VideoWidget(),
              const SizedBox(height: 10),
              TextButton(
                onPressed: () {
                  Navigator.pop(context);
                },
                child: const Text('Close'),
              ),
            ])));
  }
}

class VideoWidget extends StatefulWidget {
  const VideoWidget({Key? key}) : super(key: key);

  @override
  _VideoWidgetState createState() => _VideoWidgetState();
}

class _VideoWidgetState extends State<VideoWidget> {
  late VideoPlayerController _controller;

  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.networkUrl(
        Uri.parse('https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4'))
      ..initialize().then((_) {
        // 确保视频初始化后显示第一帧
        setState(() {});
      });

    _controller.play();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          _controller.value.isInitialized
              ? AspectRatio(
                  aspectRatio: _controller.value.aspectRatio,
                  child: VideoPlayer(_controller),
                )
              : Container(),
        ]);
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }
}

自定义数据

事件

事件通过字符串标识,可以包含可选的参数字典,这些参数将存储并随报告一起传递。

// 不带任何附加参数
Bugsee.event(name: 'payment_processed');

// 带附加自定义参数
Bugsee.event(name: 'payment_processed', parameters: <String, dynamic>{
  'amount': 125,
  'currency': 'USD'
});

跟踪

跟踪可以在问题发生前跟踪特定变量或状态的变化。

// 手动设置名为 "credit_balance" 的属性值为 15
Bugsee.trace(name: 'credit_balance', value: 15);

手动报告

您可以使用以下方法注册非致命异常:

try {
  some_code_that_throws();
} catch (ex, st) {
  await Bugsee.logException(exception: ex, handled: true, stackTrace: st);
}

Bugsee 可以进一步定制。有关更多选项和API的完整SDK文档,请访问 Bugsee Flutter 文档


更多关于Flutter崩溃报告与错误追踪插件bugsee_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter崩溃报告与错误追踪插件bugsee_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中集成并使用bugsee_flutter插件来进行崩溃报告与错误追踪的详细步骤和代码示例。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加bugsee_flutter依赖:

dependencies:
  flutter:
    sdk: flutter
  bugsee_flutter: ^最新版本号  # 请替换为实际可用的最新版本号

然后运行以下命令以获取依赖:

flutter pub get

2. 初始化Bugsee

在你的Flutter应用的入口文件(通常是main.dart)中,初始化Bugsee并配置相关参数。

import 'package:flutter/material.dart';
import 'package:bugsee_flutter/bugsee_flutter.dart';

void main() {
  // 初始化Bugsee
  Bugsee.init(
    apiKey: "你的Bugsee API密钥",  // 请替换为你的Bugsee API密钥
    enableInDebugMode: true,  // 是否在debug模式下启用Bugsee(生产环境中应设为false)
    enableLogs: true,  // 是否启用日志记录
    enableNetwork: true,  // 是否启用网络请求的捕获
    enableCrashReporting: true  // 是否启用崩溃报告
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
    // 示例:手动发送一个错误报告
    try {
      throw Exception("这是一个手动触发的错误");
    } catch (e) {
      Bugsee.logError(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '你点击了按钮 $_counter 次',
            ),
            ElevatedButton(
              onPressed: _incrementCounter,
              child: Text('点击我'),
            ),
          ],
        ),
      ),
    );
  }
}

3. 捕获和处理错误

你可以使用Bugsee.logError方法来手动捕获并发送错误报告。在上面的代码中,我们在按钮点击事件中演示了如何捕获一个异常并发送错误报告。

4. 捕获网络请求(可选)

如果你启用了网络请求的捕获(enableNetwork: true),Bugsee将自动捕获所有发出的HTTP请求和响应。

5. 其他功能

bugsee_flutter插件还提供了其他功能,如自定义日志、用户反馈等,你可以根据文档进一步探索和使用这些功能。

注意事项

  1. 隐私保护:确保你遵守相关的隐私政策和法规,不要在未经用户同意的情况下捕获敏感信息。
  2. 生产环境:在生产环境中,应将enableInDebugMode设为false,以避免不必要的日志输出和性能影响。

通过以上步骤,你就可以在Flutter项目中集成并使用bugsee_flutter插件来进行崩溃报告与错误追踪了。

回到顶部