Flutter数据分析插件simplytics的使用

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

Flutter数据分析插件simplytics的使用

Simplytics(简单分析)是一个简单的抽象层,用于分析和崩溃报告。它可以让你连接多个不同的分析和错误监控服务,如Firebase Analytics和Crashlytics,Sentry等,并且还可以将事件简单地记录到系统日志中。

特点

  • 轻松添加或替换分析/错误监控服务而无需更改应用程序代码。
  • 可以同时向多个不同的分析服务发送路由转换和事件报告。
  • 可以同时向多个错误监控服务发送崩溃和错误报告。
  • 轻松调试事件并将其发送到系统日志。
  • 轻松连接新的分析和错误监控服务。
  • 使用simplytics_firebase包轻松连接Firebase Analytics和Crashlytics。
  • 使用simplytics_sentry包轻松连接Sentry和Glitchtip。

目录

开始使用

要开始使用Simplytics,你需要配置它,并指定要使用的分析和错误监控服务类:

Simplytics.setup(
  analyticsService: SimplyticsDebugAnalyticsService(),
  crashlogService: SimplyticsDebugCrashlogService(),
);

注意! 这些设置必须在runApp()之前完成:

void main() {
  Simplytics.setup(
    analyticsService: SimplyticsDebugAnalyticsService(),
    crashlogService: SimplyticsDebugCrashlogService(),
  );

  runApp(const MyApp());
}

你可以在分析和错误监控方面使用多个服务。为此,你需要将它们包裹在一个组中:

Simplytics.setup(
  analyticsService: SimplyticsAnalyticsServiceGroup([
    SimplyticsDebugAnalyticsService(),
    CustomAnalyticsService(),
  ]),
  crashlogService: SimplyticsCrashlogServiceGroup([
    SimplyticsDebugCrashlogService(),
    CustomCrashReportingService(),
  ]),
);

对于Firebase Analytics和Crashlytics,你可以使用simplytics_firebase包中的预构建服务类:

Simplytics.setup(
  analyticsService: SimplyticsFirebaseAnalyticsService(FirebaseAnalytics.instance),
  crashlogService: SimplyticsFirebaseCrashlogService(FirebaseCrashlytics.instance),
);

如果你希望捕获所有Dart和Flutter错误和异常并将它们发送到错误监控系统,可以使用runAppGuarded()函数:

void main() {
  runAppGuarded(
    // 初始化Simplytics并创建应用类对象
    () async {
      // 设置Simplytics
      Simplytics.setup(
        analyticsService: SimplyticsDebugAnalyticsService(),
        crashlogService: SimplyticsDebugCrashlogService(),
      );

      // 创建应用类对象
      return const MyApp();
    },

    // 发送致命错误到Simplytics
    onError: (error, stackTrace) => Simplytics.crashlog.recordFatalError,
  );
}

runAppGuarded()函数使配置和捕获所有未处理的错误和异常变得容易。

它调用WidgetsFlutterBinding.ensureInitialized()(可以禁用),配置所有Dart和Flutter错误处理器,并启动应用。所有错误和异常都将通过onError参数传递给你的处理程序。

使用

发送事件

要将事件发送到分析服务,你可以使用Simplytics.analytics对象的logEvent方法:

Simplytics.analytics.logEvent(name: 'button_tapped');

你可以在事件中传递参数,这些参数是一个Map<String, Object>

Simplytics.analytics.logEvent(name: 'product_details', parameters: {'id': 1, 'name': 'Product 1'});

你可以使用resetAnalyticsData清除设备上的所有分析数据:

Simplytics.analytics.resetAnalyticsData();
跟踪路由之间的转换

要跟踪路由之间的导航,你可以在应用中使用SimplyticsNavigatorObserver观察器:

class MyApp extends StatelessWidget {

  // 创建一个Simplytics观察器实例
  static SimplyticsNavigatorObserver simplyticsObserver = SimplyticsNavigatorObserver();

  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Simplytics Demo',
      theme: ThemeData(
        primarySwatch: Colors.teal,
      ),
      home: const DemoPage(),

      // 将Simplytics观察器实例传递给navigatorObservers
      navigatorObservers: <NavigatorObserver>[simplyticsObserver],
    );
  }
}

该观察器会在当前活动的ModalRoute发生变化时发送事件到分析服务。

你可以使用nameExtractor参数配置从RouteSettings中提取路由名称的方法,也可以使用routeFilter参数过滤哪些路由之间的转换会自动发送到分析服务。

你还可以手动发送路由进入和退出事件,使用Simplytics.analytics对象的routeStartrouteEnd方法:

Simplytics.analytics.routeStart('Login Screen');
...
Simplytics.analytics.routeEnd('Login Screen');
发送错误到错误监控服务

你可以使用Simplytics.crashlog对象的recordError()方法将错误信息发送到错误监控服务:

Simplytics.crashlog.recordError('Entity not found.', StackTrace.current, reason: 'NotFoundException');
添加额外的信息到报告

在发送报告时,你可以指定额外的信息,例如自定义属性、标签等。为此,你需要将一个或多个对象传递给information参数。Simplytics提供了两个预定义的对象来描述属性和标签:

  • SimplyticsErrorProperty - 用于自定义属性;
  • SimplyticsErrorTag - 用于标签。

例如,要将报告标记为“流程”,你可以传递SimplyticsErrorTag

Simplytics.crashlog.recordError(
  'User not found.',
  StackTrace.current,
  reason: 'UserNotFoundException',
  information: [
    SimplyticsErrorTag('flow', 1),
  ],
);

属性的添加方式相同。你可以一次添加多个标签和属性:

Simplytics.crashlog.recordError(
  'User not found.',
  StackTrace.current,
  reason: 'UserNotFoundException',
  information: [
    SimplyticsErrorTag('flow', 1),
    SimplyticsErrorProperty('region', 'local'),
    SimplyticsErrorProperty('code', 321),
  ],
);

你还可以传递其他对象,如ErrorHintErrorDescriptionErrorSummaryErrorSpacer和其他任何dart对象。它们都会被转换为字符串并随报告一起发送。

依赖于错误监控服务的实现,附加到报告的额外信息可能会有所不同。例如,在Firebase Crashlytics中,标签、属性和其他对象作为附加信息块发送。在Sentry中,标签作为标签发送,这允许按标签筛选报告。

设置用户身份和自定义属性

你可以使用相应对象的setUserId方法将用户身份存储到分析和错误监控服务中:

Simplytics.analytics.setUserId('user_1');
Simplytics.crashlog.setUserId('user_1');

你还可以使用setUserPropertysetCustomKey方法为分析和错误监控服务添加自定义属性和键:

// 为分析服务设置用户属性
Simplytics.analytics.setUserProperty(name: 'prop1', value: 'value1');

// 为错误监控服务设置自定义键
Simplytics.crashlog.setCustomKey('test_key', 'test_value');

调试分析事件和错误报告

要调试事件,你可以使用SimplyticsDebugAnalyticsServiceSimplyticsDebugCrashlogService服务类,在调试编译模式(kDebugMode)下将分析事件和错误报告输出到系统日志:

Simplytics.setup(
  analyticsService: SimplyticsAnalyticsServiceGroup([
    // 在kDebugMode下将事件发送到系统日志
    SimplyticsDebugAnalyticsService(),

    CustomAnalyticsService(),
  ]),
  crashlogService: SimplyticsCrashlogServiceGroup([
    // 在kDebugMode下将事件发送到系统日志
    SimplyticsDebugCrashlogService(),

    CustomCrashReportingService(),
  ]),
);

这种行为可以通过这些类的构造函数参数进行配置:

// 始终将事件发送到系统日志
SimplyticsDebugAnalyticsService(true)

创建自己的分析和错误监控服务类

对于你自己的或其他分析和错误监控服务,你可以创建自己的服务类并在Simplytics.setup()中使用它们。

您自己的分析服务类

要创建自己的分析服务类,你需要扩展SimplyticsAnalyticsInterface接口。

以下是一个针对Firebase Analytics的分析服务类的示例实现(但你可以使用simplytics_firebase包中的预构建类):

class CustomFirebaseAnalyticsService extends SimplyticsAnalyticsInterface {
  final FirebaseAnalytics analytics;

  CustomFirebaseAnalyticsService(this.analytics);

  bool _enabled = true;

  [@override](/user/override)
  Future<void> logEvent({required String name, Map<String, Object?>? parameters}) {
    return analytics.logEvent(name: name, parameters: parameters);
  }

  [@override](/user/override)
  Future<void> resetAnalyticsData() {
    return analytics.resetAnalyticsData();
  }

  [@override](/user/override)
  Future<void> routeStart({required String name, String? screenClassOverride}) {
    return analytics.setCurrentScreen(screenName: name, screenClassOverride: screenClassOverride ?? 'Flutter');
  }

  [@override](/user/override)
  Future<void> routeEnd({required String name}) async {}

  [@override](/user/override)
  Future<void> setUserId(String? id) {
    return analytics.setUserId(id: id);
  }

  [@override](/user/override)
  Future<void> setUserProperty({required String name, required String? value}) {
    return analytics.setUserProperty(name: name, value: value);
  }

  [@override](/user/override)
  bool get isEnabled => _enabled;

  [@override](/user/override)
  Future<void> setEnabled(bool enabled) {
    _enabled = enabled;
    return analytics.setAnalyticsCollectionEnabled(enabled);
  }
}
您自己的错误监控服务类

要创建自己的错误监控服务类,你需要扩展SimplyticsCrashlogInterface接口。

以下是一个针对Firebase Crashlytics的错误监控服务类的示例实现(但你可以使用simplytics_firebase包中的预构建类):

class CustomFirebaseCrashlogService extends SimplyticsCrashlogInterface {
  final FirebaseCrashlytics crashlytics;

  CustomFirebaseCrashlogService(this.crashlytics);

  [@override](/user/override)
  Future<void> log(String message) {
    return crashlytics.log(message);
  }

  [@override](/user/override)
  Future<void> recordError(
    dynamic exception,
    StackTrace? stackTrace, {
    dynamic reason,
    Iterable<Object> information = const [],
    bool fatal = false,
  }) {
    return crashlytics.recordError(
      exception,
      stackTrace,
      reason: reason,
      information: information,
      fatal: fatal,
    );
  }

  [@override](/user/override)
  Future<void> setCustomKey(String key, Object value) {
    return crashlytics.setCustomKey(key, value);
  }

  [@override](/user/override)
  Future<void> setUserId(String identifier) {
    return crashlytics.setUserIdentifier(identifier);
  }

  [@override](/user/override)
  bool get isEnabled => crashlytics.isCrashlyticsCollectionEnabled;

  [@override](/user/override)
  Future<void> setEnabled(bool enabled) => crashlytics.setCrashlyticsCollectionEnabled(enabled);
}

具有类型安全参数的分析事件

你可以创建具有类型安全参数的自己的事件类,并在分发事件时使用它们:

Simplytics.analytics.log(PostScoreEvent(score: 7));

要做到这一点,扩展SimplyticsEvent类并实现其getEventData方法:

class PostScoreEvent extends SimplyticsEvent {
  final int score;
  final int level;
  final String? character;

  PostScoreEvent({required this.score, this.level = 1, this.character});

  [@override](/user/override)
  SimplyticsEventData getEventData(SimplyticsAnalyticsInterface service) =>
      SimplyticsEventData(
        name: 'post_score',
        parameters: {
          'score': score,
          'level': level,
          'character': character,
        },
      );
}

通过检查service参数的类型,可以为不同的分析服务发送不同的事件,并带有不同的一组参数:

class PostScoreEvent extends SimplyticsEvent {
  final int score;
  final int level;
  final String? character;

  PostScoreEvent({required this.score, this.level = 1, this.character});

  [@override](/user/override)
  SimplyticsEventData getEventData(SimplyticsAnalyticsInterface service) {
    if (service is SimplyticsFirebaseAnalyticsService) {
      return SimplyticsEventData(
        name: 'post_score',
        parameters: {
          'score': score,
          'level': level,
          'character': character,
        },
      );
    } else {
      return SimplyticsEventData(
        name: 'game_score',
        parameters: {
          'scoreValue': score,
          'gameLevel': level,
          'characterName': character,
        },
      );
    }
  }
}

示例代码

以下是完整的示例代码,展示了如何使用Simplytics插件:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:simplytics/simplytics.dart';
import 'package:simplytics_example/page_route_settings.dart';
import 'package:simplytics_example/services/custom_analytics_service.dart';
import 'package:simplytics_example/services/custom_crash_reporting_service.dart';

void main() {
  runAppGuarded(
    // 初始化Simplytics并创建应用类对象
    () async {
      // 设置Simplytics
      Simplytics.setup(
        analyticsService: SimplyticsAnalyticsServiceGroup([
          SimplyticsDebugAnalyticsService(),
          CustomAnalyticsService(),
        ]),
        crashlogService: SimplyticsCrashlogServiceGroup([
          SimplyticsDebugCrashlogService(),
          CustomCrashReportingService(),
        ]),
      );

      return const MyApp();
    },

    // 发送致命错误到Simplytics
    onError: (error, stackTrace) => Simplytics.crashlog.recordFatalError,
  );
}

class MyApp extends StatelessWidget {
  // 设置观察器
  static SimplyticsNavigatorObserver observer = SimplyticsNavigatorObserver(
    nameExtractor: (route) => (route.settings is PageRouteSettings)
        ? (route.settings as PageRouteSettings).pageName
        : route.settings.name,
    routeFilter: (route) => (route is PageRoute) || (route is RawDialogRoute),
  );

  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Simplytics Demo',
      theme: ThemeData(
        primarySwatch: Colors.teal,
      ),
      home: const DemoPage(),

      // 添加观察器到navigatorObservers
      navigatorObservers: <NavigatorObserver>[observer],
    );
  }
}

// 主演示页面

class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          children: [
            OutlinedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    // 设置`settings`以在发送到分析时设置页面名称
                    settings: const PageRouteSettings(pageName: 'Analytics Demo Page'),
                    builder: (context) => const AnalyticsDemoPage(),
                  ),
                );
              },
              child: const Text('Analytics tests'),
            ),
            OutlinedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    // 设置`settings`以在发送到分析时设置页面名称
                    settings: const PageRouteSettings(pageName: 'Error Reporting Demo Page'),
                    builder: (context) => const ErrorDemoPage(),
                  ),
                );
              },
              child: const Text('Error Reporting tests'),
            ),
            const Divider(),
            OutlinedButton(
              onPressed: () {
                showDialog(
                    context: context, builder: (context) => const TestDialog());
              },
              child: const Text('Dialog test'),
            ),
            OutlinedButton(
              onPressed: () {
                showDialog(
                  context: context,
                  // 设置`settings`以在发送到分析时设置页面名称
                  routeSettings: const PageRouteSettings(pageName: 'Dialog with a named route'),
                  builder: (context) => const TestDialog(),
                );
              },
              child: const Text('Dialog test with a named route'),
            ),
          ],
        ),
      ),
    );
  }
}

// 分析演示

class PostScoreEvent extends SimplyticsEvent {
  final int score;
  final int level;
  final String? character;

  PostScoreEvent({required this.score, this.level = 1, this.character});

  [@override](/user/override)
  SimplyticsEventData getEventData(SimplyticsAnalyticsInterface service) =>
      SimplyticsEventData(
        name: 'post_score',
        parameters: {
          'score': score,
          'level': level,
          'character': character,
        },
      );
}

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

  [@override](/user/override)
  State<AnalyticsDemoPage> createState() => _AnalyticsDemoPageState();
}

class _AnalyticsDemoPageState extends State<AnalyticsDemoPage> {
  [@override](/user/override)
  void initState() {
    super.initState();

    Simplytics.analytics.setUserId('test_user');
    Simplytics.analytics.setUserProperty(name: 'prop1', value: 'value1');
  }

  void _logEvent() {
    Simplytics.analytics.logEvent(name: 'test_event');
  }

  void _logEventWithParams() {
    Simplytics.analytics
        .logEvent(name: 'test_event', parameters: {'id': 1, 'name': 'Test'});
  }

  void _logTypeSafeEvent() {
    Simplytics.analytics
        .log(PostScoreEvent(score: 7, level: 2, character: 'Dash'));
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Analytics tests')),
      body: Center(
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisSize: MainAxisSize.min,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  const Text('Analytics Off'),
                  Switch(
                    value: Simplytics.analytics.isEnabled,
                    onChanged: (value) async {
                      await Simplytics.analytics.setEnabled(value);
                      setState(() {});
                    },
                  ),
                  const Text('Analytics On'),
                ],
              ),
              const Divider(),
              TextButton(
                onPressed: _logEvent,
                child: const Text('Log event'),
              ),
              TextButton(
                onPressed: _logEventWithParams,
                child: const Text('Log event with data'),
              ),
              TextButton(
                onPressed: _logTypeSafeEvent,
                child: const Text('Log type-safe event'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

// 错误报告演示

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

  [@override](/user/override)
  State<ErrorDemoPage> createState() => _ErrorDemoPageState();
}

class _ErrorDemoPageState extends State<ErrorDemoPage> {
  [@override](/user/override)
  void initState() {
    super.initState();

    Simplytics.crashlog.setUserId('test_user');
    Simplytics.crashlog.setCustomKey('test_key', 'test_value');
  }

  void _logError() {
    Simplytics.crashlog.log('Some log error');
  }

  void _recordError() {
    Simplytics.crashlog.recordError(
      'Some error',
      StackTrace.current,
      information: [
        ErrorHint('Error hint...'),
        ErrorDescription('Error description...'),
        ErrorSummary('Error summary...'),
        ErrorSpacer(),
        SimplyticsErrorTag('tag1', 7),
        SimplyticsErrorProperty('prop1', 'a'),
      ],
      reason: 'FakeException',
    );
  }

  void _recordFatalError() {
    Simplytics.crashlog.recordError(
      'Some error',
      StackTrace.current,
      reason: 'FakeException',
      fatal: true,
    );
  }

  void _throwException() {
    throw Exception('Some exception');
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Error Reporting tests'),
      ),
      body: Center(
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisSize: MainAxisSize.min,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  const Text('Crashlog Off'),
                  Switch(
                    value: Simplytics.crashlog.isEnabled,
                    onChanged: (value) async {
                      await Simplytics.crashlog.setEnabled(value);
                      setState(() {});
                    },
                  ),
                  const Text('Crashlog On'),
                ],
              ),
              const Divider(),
              TextButton(
                onPressed: _logError,
                child: const Text('Log error'),
              ),
              TextButton(
                onPressed: _recordError,
                child: const Text('Record error'),
              ),
              TextButton(
                onPressed: _recordFatalError,
                child: const Text('Record fatal error'),
              ),
              TextButton(
                onPressed: _throwException,
                child: const Text('Throw exception'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

// 测试对话框

class TestDialog extends StatelessWidget {
  const TestDialog({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return AlertDialog(
      content: const Text('Dialog', textAlign: TextAlign.center),
      alignment: Alignment.center,
      actionsAlignment: MainAxisAlignment.center,
      actions: [
        TextButton(
            onPressed: () => Navigator.pop(context), child: const Text('OK')),
      ],
    );
  }
}

更多关于Flutter数据分析插件simplytics的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据分析插件simplytics的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用simplytics插件进行数据分析的示例代码。请注意,simplytics是一个假设的插件名称,用于说明目的。实际中,如果simplytics不是一个真实存在的插件,你需要替换为实际存在的数据分析插件,比如firebase_analytics或其他类似插件。

不过,为了保持示例的相关性,我将基于一个假设的simplytics插件API结构来编写代码。如果simplytics确实存在,你需要参考其官方文档来调整代码。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加simplytics依赖(假设它存在于pub.dev上):

dependencies:
  flutter:
    sdk: flutter
  simplytics: ^x.y.z  # 替换为实际版本号

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

2. 初始化插件

在你的应用的主文件中(通常是main.dart),初始化simplytics插件:

import 'package:flutter/material.dart';
import 'package:simplytics/simplytics.dart';  // 假设的导入路径

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  // 初始化 Simplytics
  Simplytics.initialize('YOUR_API_KEY');  // 替换为你的API密钥
  runApp(MyApp());
}

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

3. 使用插件记录事件

在你的主页面或其他需要记录数据的组件中,使用simplytics来记录事件:

import 'package:flutter/material.dart';
import 'package:simplytics/simplytics.dart';  // 假设的导入路径

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  void _logCustomEvent() {
    // 记录一个自定义事件
    Map<String, dynamic> eventParams = {
      'category': 'user_interaction',
      'action': 'button_click',
      'label': 'home_screen_button',
      'value': 1,  // 可选,事件的值
    };
    Simplytics.logEvent(name: 'custom_event', parameters: eventParams);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Simplytics Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: _logCustomEvent,
          child: Text('Log Custom Event'),
        ),
      ),
    );
  }
}

4. 运行应用

现在,你可以运行你的Flutter应用,并点击按钮来触发事件记录。假设的simplytics插件将会把这些事件发送到你的数据分析后台。

注意

  • 实际插件使用:请确保你使用的插件名称和API与实际存在的插件一致。如果simplytics不是真实存在的插件,请参考类似插件(如firebase_analytics)的官方文档。
  • API密钥:在初始化插件时,确保使用正确的API密钥。这通常是从你的数据分析服务提供者那里获取的。
  • 事件参数:根据你的需求,调整事件参数以符合你的数据分析需求。

希望这个示例能帮助你理解如何在Flutter项目中使用数据分析插件。如果有任何进一步的问题,请随时提问!

回到顶部