如何在 Firebase 分析中跟踪 Flutter 屏幕?

Posted

技术标签:

【中文标题】如何在 Firebase 分析中跟踪 Flutter 屏幕?【英文标题】:How do I track Flutter screens in Firebase analytics? 【发布时间】:2019-09-13 18:45:40 【问题描述】:

我有一个 Flutter 应用,我正在 Flutter 上测试 Google Analytics for Firebase。

我想看看我们的用户(好吧,现在是我)正在访问的路线。我按照firebase_analytics 中的设置步骤进行操作,也检查了他们的示例应用程序。如Debug View docs

中所述,我启用了 Analytics 调试

不幸的是,我在分析调试视图中收到的仅有两种屏幕视图 (firebase_screen_class) 是 FlutterMainActivity

我希望在某个地方看到/example-1/example-2/welcome,但我没有。

这是我在 Flutter 中运行的应用程序

class App extends StatelessWidget 
  final FirebaseAnalytics analytics = FirebaseAnalytics();
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      routes: <String, WidgetBuilder>
        '/example-1': (_) => Example1(),
        '/example-2': (_) => Example2(),
        '/welcome': (_) => Welcome(),
      ,
      home: Welcome(),
      navigatorObservers: [FirebaseAnalyticsObserver(analytics: analytics)],
    );
  

【问题讨论】:

为什么你不把事件放在每个单独的屏幕上而不是做漏斗? 在你的 Screen Constructor 中添加 firebase 事件。? 【参考方案1】:

这个确切的用例在 Track Screenviews 部分下的 Firebase Analytics 文档中。

如果您的应用不为您可能希望跟踪的每个屏幕(例如在游戏中)使用单独的 UIViewController 或 Activity,则手动跟踪屏幕很有用。

这正是 Flutter 的情况,因为 Flutter 负责屏幕更新:大多数简单的 Flutter 应用程序运行一个 FlutterActivity/FlutterAppDelegate,它负责自己渲染不同的屏幕,因此让 Firebase Analytics 自动跟踪屏幕不会带来预期的效果。

就我过去的经验而言,FirebaseAnalyticsObserver 并不是很有帮助,但是,我也向您推荐check their docs again,它们确实暗示事情应该“正常工作”。我最好的猜测是它对我来说效果不佳,因为我没有在我的任何路线上使用RouteSettings*

如果FirebaseAnalyticsObserver 无法工作或无法申请您的应用,那么在过去几个月的开发过程中,下一个方法对我来说效果很好。

您可以在任何时候使用FirebaseAnalytics 设置当前屏幕,如果您使用屏幕名称调用setCurrentScreen 方法:

import 'package:firebase_analytics/firebase_analytics.dart';
// Somewhere in your widgets...
FirebaseAnalytics().setCurrentScreen(screenName: 'Example1');

作为第一次尝试,我在小部件构造函数中这样做了,但这不会很好地工作并且错误地计算了事件:如果你弹出或推送路由,堆栈中的所有小部件构造函数都将被调用,即使实际上只有顶部路由符合“当前屏幕”的条件。

为了解决这个问题,我们需要使用RouteAware 类,并且只设置当前屏幕以防它是顶部路由:要么我们的路由被添加到堆栈中,要么之前的顶部路由被弹出并且我们到达了路由.

RouteAware 带有样板代码,我们不想在所有屏幕上重复该样板代码。即使对于小型应用程序,您也有几十个不同的屏幕,所以我创建了RouteAwareAnalytics mixin:

import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter/widgets.dart';

// A Navigator observer that notifies RouteAwares of changes to state of their Route
final routeObserver = RouteObserver<PageRoute>();

mixin RouteAwareAnalytics<T extends StatefulWidget> on State<T>
    implements RouteAware 
  AnalyticsRoute get route;

  @override
  void didChangeDependencies() 
    routeObserver.subscribe(this, ModalRoute.of(context));
    super.didChangeDependencies();
  

  @override
  void dispose() 
    routeObserver.unsubscribe(this);
    super.dispose();
  

  @override
  void didPop() 

  @override
  void didPopNext() 
    // Called when the top route has been popped off,
    // and the current route shows up.
    _setCurrentScreen(route);
  

  @override
  void didPush() 
    // Called when the current route has been pushed.
    _setCurrentScreen(route);
  

  @override
  void didPushNext() 

  Future<void> _setCurrentScreen(AnalyticsRoute analyticsRoute) 
    print('Setting current screen to $analyticsRoute');
    return FirebaseAnalytics().setCurrentScreen(
      screenName: screenName(analyticsRoute),
      screenClassOverride: screenClass(analyticsRoute),
    );
  

我创建了一个enum 来跟踪屏幕(以及将枚举转换为屏幕名称的函数)。我使用枚举能够轻松跟踪所有路由,重构路由名称。使用这些枚举和函数,我可以对所有可能的值进行单元测试并强制执行一致的命名:没有意外空格或特殊字符,没有不一致的大小写。可能还有其他更好的方法来确定屏幕类值,但我采用了这种方法。

enum AnalyticsRoute  example 

String screenClass(AnalyticsRoute route) 
  switch (route) 
    case AnalyticsRoute.example:
      return 'ExampleRoute';
  
  throw ArgumentError.notNull('route');


String screenName(AnalyticsRoute route) 
  switch (route) 
    case AnalyticsRoute.example:
      return '/example';
  
  throw ArgumentError.notNull('route');

初始设置的下一步是将routeObserver 注册为navigatorObservernavigatorObserver

MaterialApp(
  // ...
  navigatorObservers: [
    routeObserver,
    // FirebaseAnalyticsObserver(analytics: FirebaseAnalytics()),
  ],
);

最后,我们可以添加我们第一个跟踪的示例路线。将with RouteAwareAnalytics 添加到您的状态并覆盖get route

class ExampleRoute extends StatefulWidget 
  @override
  _ExampleRouteState createState() => _ExampleRouteState();


class _ExampleRouteState extends State<ExampleRoute> with RouteAwareAnalytics
  @override
  Widget build(BuildContext context) => Text('Example');

  @override
  AnalyticsRoute get route => AnalyticsRoute.example;

每次添加新路由时,您都可以毫不费力地完成:首先,添加一个新的枚举值,然后 Dart 编译器会指导您接下来添加什么:添加屏幕名称和类覆盖它们各自switch-case 中的值。然后,找到正在构建路由的州,添加 with RouteAwareAnalytics,并添加 route getter。

* 我不使用RouteSettings 的原因是我更喜欢带有类型参数的Simon Lightfoot's approach,而不是设置提供的Object 参数:

class ExampleRoute extends StatefulWidget 
  const ExampleRoute._(@required this.integer, Key key) : super(key: key);
  // All types of members are supported, but I used int as example
  final int integer;
  static Route<void> route(@required int integer) =>
      MaterialPageRoute(
        // I could add the settings here, though, it wouldn't enforce good types
        builder: (_) => ExampleRoute._(integer: integer),
      );
  // ...

【讨论】:

DRY 的优点:我意识到我不能只使用 screen_view 事件来构建漏斗,所以我刚刚用额外的 analytics.logEvent(name: 'screen_view-$screenName'); 更新了我的抽象类的 setCurrentScreen 您真的可以在 Firebase 控制台中看到您的真实屏幕名称吗?我只是将“screen_name”视为事件,无论我如何使用 setCurrentScreen("whatever"); 命名事件 为什么不让 AnalyticsScreen 覆盖 StatefulWidget?这样,您可以在 AnalyticsScreen 构造函数中调用 setCurrentScreen(),从而防止您忘记对屏幕的此调用。 是否有任何已知的方法来实现 ModalRoutes 的日志记录?我的应用程序中有很多底部工作表是无状态小部件(这就是为什么我不想使用 RouteAware,因为它需要有状态小部件)并且标准 FirebaseAnalyticsObserver 不起作用,因为它只观察 PageRoutes 知道如何在无状态小部件上使用 mixin【参考方案2】:

你可以添加一个firebase分析navigation observer:

要使用它,请将其添加到 Navigator 的 navigatorObservers 中,例如如果 您正在使用 MaterialApp:

class MyApp extends StatelessWidget 
  FirebaseAnalytics analytics = FirebaseAnalytics();
...

MaterialApp(
  home: MyAppHome(),
  navigatorObservers: [
    FirebaseAnalyticsObserver(analytics: analytics),
  ],
);

注意!

如果这是您第一次在应用中集成分析,则您的分析需要大约一天才能显示在仪表板中。

立即查看结果

为了立即查看调试结果,请在终端上运行上述命令并在 firebase analytic debugView 上检查您的分析(如上图所示):

adb shell setprop debug.firebase.analytics.app [your_app_package_name]

享受吧!

【讨论】:

我没有看到实际的屏幕名称,只是屏幕截图中的 screen_name? 如果您按下其中一个 screen_view 分析,您将获得更多信息,例如时间戳、令牌和屏幕名称【参考方案3】:

我遇到这个问题有一段时间了,只是能够让它工作

我的问题是我没有正确传递 MaterialPageRoute 中的设置

return MaterialPageRoute(
      settings: RouteSettings(
        name: routeName,
      ),
      builder: (_) => viewToShow);

我按照FilledStack 上的教程进行操作,并且在看到示例代码后能够找出我的问题

【讨论】:

【参考方案4】:

如果您在 screen_viewfirebase_screen_class 参数中看到“Flutter” 事件,这意味着你已经正确配置了它。

您应该在firebase_screen 参数而不是firebase_screen_class 中找到您期望的值。

还值得检查firebase_previous_screen 参数以查看在此之前打开的屏幕是什么。

【讨论】:

以上是关于如何在 Firebase 分析中跟踪 Flutter 屏幕?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Firebase 分析跟踪 android 片段

Google Analytics for Firebase:如何分析事件 [关闭]

Firebase 不跟踪动态链接的点击次数

在 Firebase 中禁用自动活动跟踪

如何在 Firebase Analytics 中查看所有设备列表?

Firebase 中的 UTM 跟踪代码