flutter_page_tracker 1.0.0 flutter_page_tracker: ^1.0.0 copied to clipboard
A new Flutter package project.
使用 #
原理篇 #
1.概述 #
页面的埋点追踪通常处于业务开发的最后一环,留给埋点的开发时间通常并不充裕,但是埋点数据对于后期的产品调整有重要的意义,所以一个稳定高效的埋点框架是非常重要的。
2. 我们期望埋点框架所具备的功能 #
2.1 PageView,PageExit事件
我们期望当调用Navigator.of(context).pushNamed("XXX Page");
时,首先对之前的页面发送PageExit
,然后对当前页面发送PageView
事件。当调用Navigator.of(context).pop();
时则,首先发送当前页面的PageExit
事件,再发送之前页面的PageView
事件。
我们首先想到的是使用RouteObserver,但是PageView
和PageExit
发送的顺序相反。并且PopupRoute类型的路由会影响前一个页面的埋点事件发送,例如我们入栈的顺序是 A页面 -> A页面上的弹窗 -> B页面,但是在这个过程中A页面的PageExit
事件没有发送。
所以我们必须自己管理路由栈,这样判断不同路由的类型,并控制事件的顺序。详细实现方案在后面展开。
2.2 TagView组件于PageView组件
这两个组件虽然与Flutter的路由无关,但是在产品经理眼中它们任属于页面。并且当Tab发生首次曝光和切换的时候我们都需要发送埋点事件。
例如当Tab页A首次曝光时,我们首先发送上一个页面的PageExit
事件,然后发送TabA的PageView
事件。当我们从TabA切换到TabB的时候,先发送TabA的PageExit
事件,然后发送TabB的PageView
事件。当我们push一个新的路由时,需要发送TabB的PageExit
事件。
这套流程需要Tab页和普通页面之间通过事件机制来交互,如果直接把这套机制搬到业务代码中,那么业务代码中就会包含大量与业务无关并且重复的代码。详细的抽象方案见后文。
3. 解决这些问题 #
3.1 解决PageView,PageExit的顺序问题
RouteObserver给了我们一个不错的起点,我们重写其中的didPop
和didPush
方法就并调整事件发送的顺序就可以解决这个问题。详见TrackerStackObserver,在didpop
方法中我们先触发上一个路由的PageExit
事件,然后再触发当前路由的PageView
事件。
3.2 避免弹窗的干扰(例如Dialog)
在RouteObserver.didPop(Route中,我们可以通过previousRoute找到上一个路由,并更具它来发送上一个路由的PageView事件。但是如果上一个路由是Dialog
,就会造成错误,因为我们实际想要的是包含这个Dialog
的路由。
要解决这个问题我们必须自己维护一个路由栈,这样当didPop
触发时我们就可以找到真正的上一个路由。请参考这一段代码,这里的routes
是当前的路由栈。
3.3 如何上报TabView中的埋点事件,并和其它页面串联起来
这个问题可以分解为两个小问题:
-
- 如何把TabView页面和普通的路由进行串联?
-
- 当Tab发生切换时如何发送埋点事件?
为了解决这两个问题,我们需要一个容器来管理tab页面的状态并且承载事件转发的任务。详见下图: 。
其中TabsWrapper会监听来自Flutter的路由事件,并转发给当前曝光的Tab,这就可以解决了问题一。
同时TabsWrappe也会包含一个TabController
和上一个被打开的Tab索引,TabsWrappe会监听来自TabController
的onChange(index)事件,并把事件转发给对应的tab,这就解决了问题二。