开源|Magpie可视化圈选埋点实践
开源项目专题系列(八)
1.开源项目名称:magpie_log2.github地址:
https://github.com/wuba/magpie_log
3.简介:magpie_log是基于flutter的一个跨平台可视化圈选埋点的解决方案。旨在解决手动埋点耦合业务,现有Native自动埋点方案无法带参,以及混合开发中因埋点导致交互频繁影响性能等问题,成为flutter埋点的一站式解决方案。live58技术沙龙活动第五期“Flutter在58的应用实践系列话题”本周日晚7:00准时开幕点击图片即可报名抢座
全文大纲如下:
项目背景 项目架构 具体实现细节 流程与展示 展望 总结 作者介绍
项目背景
现有的自动埋点方案,主要可以分为两类:一种是基于动态代理的可视化埋点,一种是基于ASM的全埋点方案。两者的主要区别就是全埋点支持回溯,可视化不支持。相对的,可视化埋点可以可视化配置需要上传的数据,全埋点方案比较耗流量和性能。经过调研,全埋点上传的数据大部分是不会使用的,但我们又需要可视化的页面来方便操作,因此基于可视化埋点的思路,并结合flutter的特色进行了优化改造。
确定选型之后就是一些具体的方案和思考:
如何拦截尽可能多的事件,native拦截onClick能不能在flutter用,如何用?
native的圈选痛点无法带与ui无关的参数,flutter是基于MVVM的架构是否可以通过ViewModel实现圈选带参?
可视化如何做,在服务端还是客户端做?
如果是Hybrid形式接入flutter,如何做到和原有埋点系统无缝衔接,并且减少通讯频次?
带着这些问题和思考,不断的调研,实践,最终设计了magpie_log的整体架构。
项目架构
图3 项目架构
首先解决如何拦截尽可能多的事件,选择实现基于redux的action拦截、基于Navigator的跳转拦截和setState()拦截,同时为了覆盖全埋点,magpie_log还提供手动埋点,后面会详细说明为什么怎么做;
如何解决圈选带参,由于是MVVM的模式,view绑定着页面级别的ViewModel(如Redux有全局的store数据),也就是说可以通过View拿到对应的ViewModel数据,进而实现带参;
如何实现可视化,由于开发成本的原因,magpie_log最终选择在native页面实现圈选操作,native界面相对较小,但是通过UE同学的设计尽可能要方便用户操作,并且功能全面,加入了配置,管理等功能;
为了解决通讯频繁的问题我们了设计定时器,计数器减少交互,为了解决无缝衔接,快速接入的问题,magpie_log分别实现native,flutter的上报封装使得接入十分方便。
具体实现细节解析
图4 细节解析
下面主要介绍各种功能的具体实现细节:
1、圈选拦截
首先也是最关键的一个问题,就是如何拦截尽可能多的事件。基本上开始的第一周都是在圈选拦截的技术选型。什么样的技术选型最适合呢?
首先想到的肯定是native的思路,通过AOP的思想,拦截OnClick事件,但是很快发现拦截所有的事件就很困难,而且即使拦截Detector,也获取不到树形结构,因为flutter的widget本身是拿不到层级结构的,element可以,但是我们能拦截到的是widget,通过widget获取不到element。也就是说view的唯一标识无法确认。总结一下就是思路不清晰,实现困难,逆天而行。
最后我们几经波折想到了大部分flutter的应用都会引用状态管理,其中最常用的是redux,并且通过redux可以拦截所有的action事件,并在中间件或者reducer里面处理逻辑;符合mvvm的设计模式;唯一标识可以通过actionName和页面路由做唯一的标识。这种实现方式思路清晰,实现也相对简单,成本最低。这样项目才算开始走上正轨。
由于的主要圈选事件的触发是基于redux,先介绍一下redux:
很多做flutter开发的同学都遇到过这个问题,就是如图9所示,当子控件触发事件通知其他组件更新,会调用跟控件的setState,所有的子View都会刷新,无法实现局部刷新。
当项目十分庞大,页面更新会很混乱,耦合严重,因此官方有提出了flutter-redux状态管理插件,底层是Inheritedwighet,很好的解决了这些问题,想要了解的可以看官方的文档,这里不赘述。
当然redux也有很多的问题,我在后面会讲到一些优化的方案。
2、参数级联勾选
native的自动埋点方案的一个很大的问题就是可带参数有限,而且可选的参数必须是和UI密切相关的;然而如果基于redux状态管理,获取参数就有了契机,有全局的store数据,在拦截事件的同时能过获取store数据,并且通过store的层级数据做递归处理,使得数据层次化,进而在页面展示,可供用户进行圈选。
3、列表形式拦截
列表形式的数据也是自动埋点的一个难点,包括遍历以及上报数据的过程,现阶段的处理方式是在配置阶段对list的数据进行特殊处理。取list的第一条数据做配置规范,触发点击等事件的时候需要传递index参数,表明点击的位置,这样方便统计。
4、setState()拦截
如果你真的真的没有选择redux做状态管理,magpie_log也提供了setState的拦截方式———WidgetLogState。需要继承,并且实现对应的方法,可以说耦合比较重,并不建议过多的使用。
5、页面跳转拦截
除了点击展示等事件,页面的曝光统计也是非常常见的埋点场景,因此magpie_log也支持页面的统计。实现方式主要就是基于Navigator,需要设置LogObserver监听。当监听到页面push操作时,debug模式拦截唤起圈选页面,Magpie_log通过pop和push并维护了一个自己的页面堆栈,页面堆栈主要是用于获取当前路由标识,标识埋点的唯一性。
6、手动埋点
MagpieStatisticsHandler.instance.writeData({'data': '手动埋点数据示例'});
所有的自动埋点都不能保证覆盖所有的埋点,因此我们也提供了手动埋点的api,方便统一上传管理。
7、圈选配置
圈选配置的主要分4个部分,埋点配置,配置文件,基础配置和上报配置。
埋点配置是有一个个埋点的配置项组成,包括标识,路由,类型组成的唯一标识,以及参数和备注。
配置文件的管理是分页面ui配置Api,内存缓存,磁盘和assets5个部分,初始化配置是从assest取出配置文件到磁盘,同步内存,所有页面操作者api接口大都是和内存打交道,只有最后生成文件保存的时候做持久化存储,避免过多的交互。
基础配置指的是一些ui上面可控制的配置。
8、埋点上报
埋点上报单独拿出来,为了说明除了flutter侧的回调,避免native和flutter过多的交互影响性能,magpie_log提供逐条上报,定时上报,计数上报的选项,同时为了解决大多项目都是混合开发的模式,解决已有native系统的问题,并且提供了Android和ios的channelApi,方便或者项目的引用。
流程与展示
简单来说,流程只需要4部分,既触发、圈选、配置和运行时上报:
详细工作流程可以参考下面的图15:
随着App打开,进行配置文件的初始化,主要工作是把assets里面的文件转移到磁盘。当用户触发Action事件,会根据用户当前是debug还是release,如果是debug会走圈选配置的流程,最后生成埋点的配置文件;如果是release模式会走线上埋点的上报流程,当然前提是你有相关的对应配置。
下面是对应流程的展示:
图16 展示
展望
跨平台的更加全面的动态化可视化的圈选埋点解决方案:
动态化:服务端配合,动态化配置的上传和下发;
全面:redux一个App一个store对业务并行开发并不友好,改造redux;
级联赋值问题 导致日志参数和数据一样,可以增加用户配置.
总结
项目已开源!开源地址:
https://github.com/wuba/magpie_log
END
阅读推荐