Flutter崩溃报告插件raygun4flutter的使用

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

Flutter崩溃报告插件raygun4flutter的使用

Flutter应用在开发和发布后,可能会遇到各种各样的错误。为了能够快速定位并修复这些问题,使用一个可靠的崩溃报告工具是非常重要的。raygun4flutter就是这样一个强大的工具,它可以帮助开发者捕获和分析Flutter应用中的异常,并将这些信息发送到Raygun平台进行处理。

一、简介

  • 版本信息Pub Version
  • CI状态CI

raygun4flutter是世界上最好的Flutter崩溃报告解决方案之一,适用于Dart SDK 3.3.0及以上版本。从1.0.0版本开始,该库增加了对Flutter桌面端和Web的支持,尽管官方表示这些平台上的支持仍在完善中,但初步测试表明其工作正常。如果有任何问题或建议,欢迎通过GitHub反馈。

二、安装与配置

1. 添加依赖

首先,在命令行中执行以下命令来添加raygun4flutter作为项目的依赖项:

$ flutter pub add raygun4flutter

这将在pubspec.yaml文件中自动添加如下内容(其中x.y.z代表具体的版本号):

dependencies:
  raygun4flutter: ^x.y.z

接着,在Dart代码中导入此库:

import 'package:raygun4flutter/raygun4flutter.dart';

2. 平台特定注意事项

Android

确保在/android/src/main目录下的AndroidManifest.xml文件中包含互联网访问权限声明:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

三、初始化与使用

初始化

在应用程序启动时调用Raygun.init()方法,并传入API密钥以初始化Raygun客户端。例如,在initState()方法中实现:

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    Raygun.init(apiKey:'your_api_key_here', version:'app_version');
  }
}

这里还可以选择性地设置应用程序版本号,以便更好地跟踪不同版本间的崩溃情况。

错误捕捉与发送

为了确保所有未被捕获的Flutter框架内部错误都能被正确上报给Raygun,在主函数中添加自定义的FlutterError.onError处理器:

FlutterError.onError = (details) {
  // 默认错误处理逻辑
  FlutterError.presentError(details);

  // 将错误转发给Raygun
  Raygun.sendException(
    error: details.exception,
    stackTrace: details.stack,
  );
};

此外,对于发生在Flutter框架之外的异步代码中的Dart错误,则可以通过runZonedGuarded包裹整个应用程序入口点的方式来捕获:

runZonedGuarded<Future<void>>(() async {
  runApp(const MyApp());
}, (Object error, StackTrace stackTrace) {
  Raygun.sendException(
    error: error,
    stackTrace: stackTrace,
  );
});

这种方式不仅适用于Release模式,也能够在Debug模式下有效工作。

手动发送错误

除了自动捕获异常外,开发者也可以根据需要主动触发错误报告。例如,在发生特定业务逻辑失败时:

try {
  // 某些可能导致异常的操作
} catch (error) {
  Raygun.sendException(error: error);
}

甚至可以构造完全自定义的错误对象并通过sendCustom()方法发送:

Raygun.sendCustom(
  className: 'MyApp',
  reason: 'test error message',
  tags: ['API','Tag2'],
  customData: {'custom1': 'value', 'custom2': 42,},
  stackTrace: StackTrace.current,
  innerError: Exception('Inner Error!'),
);

四、高级功能

  • 标签和自定义数据:可以为每个错误报告设置全局或局部的标签及自定义键值对,用于更精细地分类和过滤。
  • 面包屑记录:允许插入一系列操作日志(即“面包屑”),帮助理解导致崩溃前的应用行为。
  • 用户信息关联:当某个真实用户遇到了程序故障时,可以通过设定用户名等信息让Raygun知道是谁遇到了问题。
  • 发送前回调:提供了一个钩子函数onBeforeSend,可以在最终提交之前修改即将发送的数据包内容,或者直接取消此次上传。

五、完整示例

下面是一个完整的Flutter项目示例,展示了如何集成并使用raygun4flutter进行崩溃监控:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:raygun4flutter/raygun4flutter.dart';

void main() {
  // 配置Flutter框架内的错误报告机制
  FlutterError.onError = (details) {
    FlutterError.presentError(details);
    Raygun.sendException(error: details.exception, stackTrace: details.stack);
  };

  // 捕捉非Flutter框架内的Dart错误
  runZonedGuarded<Future<void>>(() async {
    runApp(const MyApp());
  }, (Object error, StackTrace stackTrace) {
    Raygun.sendException(error: error, stackTrace: stackTrace);
  });
}

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

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

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    Raygun.init(apiKey: 'your_api_key_here', version: '1.2.3');
    Raygun.setTags(['tag1', 'tag2']);
    Raygun.setCustomData({'custom': 'data'});

    Raygun.onBeforeSend = (payload) {
      final message = payload.details.error?.message;
      debugPrint('Sending: $message');

      payload.details.breadcrumbs.removeWhere(
        (breadcrumb) => breadcrumb.message.contains('some-confidential-data'),
      );

      if (message?.contains('some-pattern') ?? false) {
        return null;
      }

      return payload;
    };
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Raygun4Flutter Example')),
        body: Column(
          children: <Widget>[
            ElevatedButton(
              onPressed: () {
                throw StateError('This is a Dart exception.');
              },
              child: const Text('Cause Dart Exception'),
            ),
            ElevatedButton(
              onPressed: () async {
                Future<void> foo() async {
                  throw StateError('This is an async Dart exception.');
                }

                Future<void> bar() async {
                  await foo();
                }

                await bar();
              },
              child: const Text('Cause Async Dart Exception'),
            ),
            ElevatedButton(
              onPressed: () {
                Raygun.sendCustom(className: 'MyApp', reason: 'test error message');
              },
              child: const Text('Send Custom Error'),
            ),
            ElevatedButton(
              onPressed: () {
                Raygun.sendCustom(
                  className: 'MyApp',
                  reason: 'test error message',
                  stackTrace: StackTrace.current,
                );
              },
              child: const Text('Send Custom Error With StackTrace'),
            ),
            ElevatedButton(
              onPressed: () {
                Raygun.sendCustom(
                  className: 'MyApp',
                  reason: 'test error message',
                  tags: ['myTag1', 'myTag2'],
                  customData: {'custom1': 'value', 'custom2': 42,},
                  stackTrace: StackTrace.current,
                  innerError: const MyCustomException('Custom exception'),
                );
              },
              child: const Text('Send Custom Error With All Options'),
            ),
            ElevatedButton(
              onPressed: () {
                Raygun.recordBreadcrumb('test breadcrumb');
                Raygun.recordBreadcrumbObject(
                  RaygunBreadcrumbMessage(
                    message: 'message',
                    category: 'category',
                    level: RaygunBreadcrumbLevel.warning,
                    customData: {'custom': 'data'},
                  ),
                );
              },
              child: const Text('Breadcrumb'),
            ),
            ElevatedButton(
              onPressed: () {
                Raygun.setUserId('1234');
              },
              child: const Text('Set User Id'),
            ),
            ElevatedButton(
              onPressed: () {
                Raygun.setUser(
                  RaygunUserInfo(
                    identifier: '1234',
                    firstName: 'FIRST',
                    fullName: 'FIRST LAST',
                    email: 'test@example.com',
                  ),
                );
              },
              child: const Text('Set RaygunUserInfo'),
            ),
            ElevatedButton(
              onPressed: () {
                Raygun.setUser(null);
              },
              child: const Text('Set Anonymous User'),
            ),
          ],
        ),
      ),
    );
  }
}

class MyCustomException implements Exception {
  const MyCustomException(this.message);

  final String message;

  @override
  String toString() {
    return 'MyCustomException: $message';
  }
}

以上就是关于raygun4flutter的基本介绍及其在Flutter项目中的具体应用方式。希望这篇文章能帮助你更好地理解和使用这个优秀的崩溃报告工具!


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

1 回复

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


在Flutter项目中集成Raygun4Flutter插件以便捕获和处理崩溃报告,可以按照以下步骤进行。这里提供一个简单的代码案例来展示如何配置和使用Raygun4Flutter。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加Raygun4Flutter的依赖:

dependencies:
  flutter:
    sdk: flutter
  raygun4flutter: ^最新版本号  # 请替换为最新的版本号

然后运行flutter pub get来安装依赖。

2. 配置Raygun

在你的Flutter应用的入口文件(通常是main.dart)中,配置Raygun客户端。你需要提供你的Raygun API密钥。

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

void main() {
  // 初始化Raygun客户端
  RaygunClient raygun = RaygunClient.newInstance('你的Raygun API密钥');
  
  // 捕获未处理的异常
  FlutterError.onError = (FlutterErrorDetails details) {
    raygun.sendError(details.exception, details.stack, {
      'error_details': details.exceptionAsString(),
      'informational_key': 'informational_value',
    });
    Zone.current.handleUncaughtError(details.exception, details.stackTrace);
  };

  // 捕获全局异常
  runZonedGuarded(() {
    runApp(MyApp());
  }, (error, stackTrace) {
    raygun.sendError(error, stackTrace, {
      'error_info': 'Global error caught',
    });
  });
}

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

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Demo Home Page'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // 模拟一个崩溃
            throw UnimplementedError('Simulated crash');
          },
          child: Text('Crash Now'),
        ),
      ),
    );
  }
}

3. 发送自定义错误(可选)

你可以在应用的任何地方发送自定义错误到Raygun。例如:

void someFunctionThatMightFail() {
  try {
    // 一些可能会失败的代码
    throw Exception('Something went wrong!');
  } catch (error, stackTrace) {
    raygun.sendError(error, stackTrace, {
      'custom_data': 'Additional information about the error',
    });
  }
}

注意事项

  1. 隐私和安全:确保在发送崩溃报告时,不包含任何敏感信息,比如用户密码、信用卡号等。
  2. 测试:在发布应用到生产环境之前,确保在开发或测试环境中充分测试Raygun的集成,以验证崩溃报告是否正确发送。
  3. 更新依赖:定期检查并更新Raygun4Flutter插件到最新版本,以获取最新的功能和安全修复。

通过以上步骤,你应该能够在Flutter应用中成功集成Raygun4Flutter插件,并捕获和处理崩溃报告。

回到顶部