flutter 插件崩溃收集——sentry_flutter 基础
一、sentry_flutter 核心功能
Sentry 是业界领先的错误追踪和性能监控平台,支持:
-
✅ 自动捕获 Flutter 框架异常 -
✅ 捕获 Dart 未处理异常 -
✅ 原生崩溃收集(iOS/Android) -
✅ 性能监控(APM) -
✅ 用户行为追踪(Breadcrumbs) -
✅ Release 健康度监控
二、安装配置
1. 添加依赖
dependencies:sentry_flutter:^8.0.0
2. 环境变量配置
在 .env.example 中添加:
# Sentry 配置SENTRY_DSN=https://your-dsn@sentry.io/project-idSENTRY_ENVIRONMENT=development
在 .env.dev、.env.prod 中配置对应环境的 DSN:
# .env.devSENTRY_DSN=https://dev-dsn@sentry.io/123456SENTRY_ENVIRONMENT=development# .env.prodSENTRY_DSN=https://prod-dsn@sentry.io/789012SENTRY_ENVIRONMENT=production
三、初始化配置
1. 创建 Sentry 服务
// lib/services/sentry_service.dartimport'package:flutter/foundation.dart';import'package:flutter_dotenv/flutter_dotenv.dart';import'package:sentry_flutter/sentry_flutter.dart';classSentryService{static Future<void> init() async {final dsn = dotenv.env['SENTRY_DSN'];final environment = dotenv.env['SENTRY_ENVIRONMENT'] ?? 'development';if (dsn == null || dsn.isEmpty) { debugPrint('⚠️ Sentry DSN 未配置,跳过初始化');return; }await SentryFlutter.init( (options) { options.dsn = dsn; options.environment = environment;// 采样率配置 options.tracesSampleRate = environment == 'production' ? 0.2 : 1.0; options.sampleRate = 1.0; // 错误事件采样率// 自动捕获配置 options.enableAutoSessionTracking = true; options.sessionTrackingIntervalMillis = 30000;// 性能监控 options.enableAutoPerformanceTracing = true;// 调试模式 options.debug = kDebugMode;// 附加上下文 options.attachScreenshot = true; options.attachViewHierarchy = true;// 过滤敏感信息 options.beforeSend = (event, hint) {// 可以在这里过滤或修改事件return event; }; }, ); debugPrint('✅ Sentry 初始化成功 - 环境: $environment'); }/// 设置用户信息staticvoid setUser({ required String id,String? email,String? username,Map<String, dynamic>? extras, }) { Sentry.configureScope((scope) { scope.setUser(SentryUser( id: id, email: email, username: username, data: extras, )); }); }/// 清除用户信息(退出登录时调用)staticvoid clearUser() { Sentry.configureScope((scope) { scope.setUser(null); }); }/// 设置标签staticvoid setTag(String key, String value) { Sentry.configureScope((scope) { scope.setTag(key, value); }); }/// 设置上下文staticvoid setContext(String key, Map<String, dynamic> context) { Sentry.configureScope((scope) { scope.setContexts(key, context); }); }/// 手动捕获异常static Future<void> captureException(dynamic exception, {dynamic stackTrace,String? hint,Map<String, dynamic>? extras, }) async {await Sentry.captureException( exception, stackTrace: stackTrace, hint: hint != null ? Hint.withMap({'message': hint}) : null, withScope: (scope) {if (extras != null) { extras.forEach((key, value) { scope.setExtra(key, value); }); } }, ); }/// 手动发送消息static Future<void> captureMessage(String message, { SentryLevel level = SentryLevel.info,Map<String, dynamic>? extras, }) async {await Sentry.captureMessage( message, level: level, withScope: (scope) {if (extras != null) { extras.forEach((key, value) { scope.setExtra(key, value); }); } }, ); }/// 添加面包屑(用户行为追踪)staticvoid addBreadcrumb({ required String message,String? category, SentryLevel level = SentryLevel.info,Map<String, dynamic>? data, }) { Sentry.addBreadcrumb(Breadcrumb( message: message, category: category, level: level, data: data, timestamp: DateTime.now(), )); }}
四、集成到 main.dart
// lib/main.dartimport'package:flutter/material.dart';import'package:sentry_flutter/sentry_flutter.dart';import'package:my_flutter_app/services/sentry_service.dart';Future<void> main() async { WidgetsFlutterBinding.ensureInitialized();// 加载环境变量await dotenv.load(fileName: ".env");// 初始化 Sentryawait SentryService.init();// 使用 Sentry 包裹 runAppawait SentryFlutter.init( (options) {// 配置已在 SentryService.init() 中完成 }, appRunner: () => runApp(// Sentry 会自动捕获 Flutter 框架异常 DefaultAssetBundle( bundle: SentryAssetBundle(), child: const MyApp(), ), ), );}
五、实战示例
1. 自动捕获异常
// lib/pages/day63_sentry_basic_demo.dartimport'package:flutter/material.dart';import'package:my_flutter_app/services/sentry_service.dart';classDay63SentryBasicDemoextendsStatelessWidget{const Day63SentryBasicDemo({super.key});@override Widget build(BuildContext context) {return Scaffold( appBar: AppBar(title: const Text('Day 63: Sentry 基础')), body: ListView( padding: const EdgeInsets.all(16), children: [ _buildSection( title: '1. 自动捕获异常', children: [ ElevatedButton( onPressed: () {// 这个异常会被 Sentry 自动捕获throw Exception('测试自动捕获异常'); }, child: const Text('触发未捕获异常'), ),const SizedBox(height: 8), ElevatedButton( onPressed: () {// 空指针异常String? nullString;print(nullString!.length); }, child: const Text('触发空指针异常'), ), ], ),const Divider(height: 32), _buildSection( title: '2. 手动上报异常', children: [ ElevatedButton( onPressed: () async {try {// 模拟业务异常await _simulateApiError(); } catch (e, stackTrace) {// 手动上报到 Sentryawait SentryService.captureException( e, stackTrace: stackTrace, hint: '用户登录失败', extras: {'user_action': 'login','timestamp': DateTime.now().toIso8601String(), }, ); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('异常已上报到 Sentry')), ); } }, child: const Text('手动捕获并上报异常'), ), ], ),const Divider(height: 32), _buildSection( title: '3. 发送消息', children: [ ElevatedButton( onPressed: () async {await SentryService.captureMessage('用户完成了重要操作', level: SentryLevel.info, extras: {'action': 'purchase','amount': 99.99, }, ); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('消息已发送到 Sentry')), ); }, child: const Text('发送信息消息'), ),const SizedBox(height: 8), ElevatedButton( onPressed: () async {await SentryService.captureMessage('检测到异常行为', level: SentryLevel.warning, extras: {'suspicious_activity': true,'ip': '192.168.1.1', }, ); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('警告消息已发送')), ); }, child: const Text('发送警告消息'), ), ], ),const Divider(height: 32), _buildSection( title: '4. 用户信息绑定', children: [ ElevatedButton( onPressed: () { SentryService.setUser( id: 'user_12345', email: 'user@example.com', username: 'john_doe', extras: {'vip_level': 'gold','registration_date': '2024-01-01', }, ); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('用户信息已设置')), ); }, child: const Text('设置用户信息'), ),const SizedBox(height: 8), ElevatedButton( onPressed: () { SentryService.clearUser(); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('用户信息已清除')), ); }, child: const Text('清除用户信息'), ), ], ),const Divider(height: 32), _buildSection( title: '5. 标签和上下文', children: [ ElevatedButton( onPressed: () { SentryService.setTag('page', 'home'); SentryService.setTag('feature', 'payment'); SentryService.setContext('device', {'model': 'iPhone 14 Pro','os': 'iOS 17.0','battery': '85%', }); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('标签和上下文已设置')), ); }, child: const Text('设置标签和上下文'), ), ], ), ], ), ); } Widget _buildSection({ required String title, required List<Widget> children, }) {return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ),const SizedBox(height: 12), ...children, ], ); } Future<void> _simulateApiError() async {await Future.delayed(constDuration(milliseconds: 500));throw Exception('API 请求失败: 网络超时'); }}
六、生产环境最佳实践
1. 环境区分
// 根据环境调整采样率options.tracesSampleRate = environment == 'production' ? 0.2 : 1.0;
2. 敏感信息过滤
options.beforeSend = (event, hint) {// 过滤密码、token 等敏感信息if (event.request?.data != null) {final data = event.request!.data asMap<String, dynamic>; data.remove('password'); data.remove('token'); }return event;};
3. 用户登录时绑定信息
// 登录成功后SentryService.setUser( id: user.id, email: user.email, username: user.name,);// 退出登录时SentryService.clearUser();
七、总结
1. DSN 在哪里获取?
登录 sentry.io → 创建项目 → 选择 Flutter → 复制 DSN
2. 如何测试 Sentry 是否正常工作?
// 触发一个测试异常throw Exception('Sentry 测试异常');
然后在 Sentry 控制台查看是否收到事件。
3. 生产环境建议
-
✅ 使用环境变量管理 DSN -
✅ 设置合理的采样率(避免流量浪费) -
✅ 过滤敏感信息 -
✅ 绑定用户信息(便于定位问题) -
✅ 使用 Release 版本号(便于追踪版本问题)
八、总结
|
|
|
|---|---|
|
|
|
|
|
captureException()
captureMessage() |
|
|
setUser()
|
|
|
setTag()
setContext() 添加业务信息 |
|
|
|
下一篇:Day 64 – 性能监控与面包屑追踪 🚀
九、国产替代方案建议
由于网络环境、合规性或访问速度等原因,国内开发者在进行选型时,可以参考以下国产替代产品:
|
|
|
|
|
|---|---|---|---|
| 崩溃收集 | Sentry
|
腾讯 Bugly |
|
| 云开发/后端 | Supabase
|
腾讯云开发 (CloudBase) |
|
| 推送通知 |
|
极光推送 (JPush)
|
|
| 合规监控 |
|
友盟+ (U-App)
|
|
[!TIP]选型建议:
海外/出海项目:强烈推荐 Sentry + Supabase,生态成熟,国际化支持完美。 国内纯本土项目:建议考虑 腾讯 Bugly + 腾讯云开发,能解决网络链路和安卓推送的“最后一公里”问题。
夜雨聆风