移动端无痕埋点实践详解(一)

用户数据埋点的一般解决思路是使用代码手动埋点。国内主要的第三方数据分析服务商,如百度统计、友盟、TalkingData等都提供这一方案。但是使用代码手动埋点的方式,投入资源大,往往很难能够有实际产出。其中一个很重要的原因其实是在分析实际业务数据之前,很难知道我真正想看什么样的数据。用代码手动的埋点方案经常会导致一个尴尬的解决,想要看的数据没有埋,埋了的数据不准。
用户数据埋点是少见的涉及到一个产品研发团队所有角色的项目。从运营的数据需求,到产品经理的抽象和规范,到移动端前端的手动采集数据,再到服务端和大数据的存储和转换,最终把结果反馈给运营和产品经理。埋点的实际产出涉及到几乎所有部门,如果按照链式的工作流来解决埋点问题,当任何一个环节出现问题,都会对整个项目结果的产出产生影响。这篇文章记录了无痕埋点方案的思路与其核心问题的解决方案。

0x01 什么是无痕埋点?

所谓的”无痕埋点”,其实就是通过技术手段,无差别的记录用户在产品中的行为,当有一天突然想对某一个控件做点击分析时,不再需要开发手动添加数据采集信息。因为从部署埋点方案的时候,就一直在收集所有的用户的数据了。用户的数据并不是分析需求产生的那一刻才有的。无痕埋点在无差别的记录用户所有行为,而实际的埋点结果产出取决于BI工程师对无痕埋点数据的清洗。

从技术角度总结以往埋点项目结果产出困难的原因,这些也是无痕埋点方案想要解决的核心问题。

  • 通过代码手动埋点比较原始,出错概率较高。
  • 埋点链路较长,出现错埋漏埋需要重新发布
  • 埋点数据准确性无法校验

所以,在项目上使用无痕埋点来解决项目链路过长的问题的方法是将埋点数据的产生过程分成两个并行的部分。将数据的采集过程前置,不再依赖运营和产品经理的需求产出。现有全量用户数据,再由运营和产品分析数据产出结果。

0x02 移动端无痕埋点如何实现?

移动端埋点的方案以在Android系统上实现为例,关键在于解决2个问题:

  • 如何统一标识控件
  • 统一拦截用户操作行为。这里说的用户操作主要还是用户的单击事件。

2.1 如何标识控件

为了自动生成事件标识,我们需要获取每个控件自身的ID、类名以及位于所属父组件的Index等特征信息,并逐级向上遍历找到根节点。约定控件标识的生成规则为 /root/ClassName:id/ClassName:id,以某一个业务界面的扫一扫按钮为例,寻找它到root节点的控件路径,它的控件标识字符串应该是 /root/RelativeLayout:-1/FrameLayout:1997209645/RelativeLayout:-1/RelativeLayout:1997209836/LinearLayout:1997209965/TextView:1997209967,并通过md5算法将这个标识字符串生成为XPATH就是我们想要的控件标识。当后台上报数据中包含1e3cdc9499fac8088220756a46c85599的点击时。我们就认为是扫一扫控件被点击了。

2.2 如何统一拦截单击事件

还是以Android端上的实现为例,如何统一拦截用户的单击事件呢?先看如何实现一个单击操作的响应,在Android上一般的做法是针对View设置一个单击的监听。

1
2
3
4
5
6
7
8
9
10
11
/**
* Interface definition for a callback to be invoked when a view is clicked.
*/
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
}

那么有没有办法统一把所有的单击事件都替换掉呢?在运行时!业务开发的工程师还是按照原生Android系统的api实现对单击事件的响应,埋点SDK在运行时统一替换所有的View.OnClickListener,将其替换成原有View.OnClickListener的包装。当执行AutoTraceListenerWrapper的时候实际执行的还是原有Listener的单击事件,同时又能统一拦截所有的单击事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class AutoTraceListenerWrapper implements View.OnClickListener {

private View.OnClickListener mClickListener;

public AutoTraceListenerWrapper(View.OnClickListener listener) {
mClickListener = listener;
}

@Override
public void onClick(View view) {
onViewClick(view);

if (mClickListener != null) {
mClickListener.onClick(view);
}
}
}

那么如何统一替换所有的View的单击监听呢?只需要遍历安卓视图结构的View Tree,使用反射机制替换掉所有的原生OnClickListener就可以了。

0x03 总结

埋点问题是不能通过一个方案适配所有业务场景的,不同的场景下需要选择不同的埋点方案。无痕埋点方案针对的是用户的简单用户行为事件,比如如何规范采集用户的点击事件。例如针对页面跳转的事件统计还是需要你单独埋点。埋点数据能不能最终完美的呈现依赖的不单单是技术方案,还有更多的是数据规范的问题。例如在面对运行时才能获知的业务信息时,如何使用埋点技术将需要的业务信息做统一的上报,是另一个重要的关键点。例如在做数据清洗时如何建立规范的数据中间表?无痕埋点只是获取完整埋点数据的第一步。

移动端无痕埋点实践详解(二)

0x04 参考文档

美团点评前端无痕埋点实践

数据采集与埋点简介之 代码埋点、可视化埋点与无痕埋点

0x05 转载请标明出处病已blog https://ivonhoe.github.io/

转载请标明出处病已blog https://ivonhoe.github.io/