简单记录下埋点几种方案,详情参考《Android全埋点解决方案》
采集信息
采集事件:页面浏览事件/前后台切换事件/点击事件
设备id:
事件时间
属性{
库版本
app名称
app版本
手机系统:
手机厂商
手机型号
系统版本
屏幕宽度
屏幕高度
页面全类名
页面名称
控件类型
控件id
控件名称
}
页面埋点
在application的onCreate中,注册registerActivityLifecycleCallbacks
在onActivityResumed中提交页面埋点信息。
多进程前后台埋点
跨进程通信状态:
事件结束状态:切到后台true,前台false
切到后台时间:onActivityPaused的时间
app启动uri
前台
onActivityStarted->结束状态为true->更新结束状态为false->发送前台事件
后台
onActivityPaused->启动倒计时,更新后台时间
倒计时结束->发送后台事件
onActivityStarted->
计算时差=当前时间-切到后台时间,
时差大于阈值并且结束状态为false->发送后台事件
取消倒计时:
onActivityStarted->更新App启动uri为true
监听app启动uri变化->uri相等则取消倒计时
缺点:
卸载会丢失后台事件
事件埋点
代理View.OnClickListener
onActivityResumed->获取到content->遍历content->view有点击事件->反射获取view点击事件,将原事件包装,将包装事件设置到view
解决onResume之后动态创建的View点击事件:
onActivityResumed->获取DecorView添加ViewTreeObserver.OnGlobalLayoutListener监听器,当布局发生变化回调->走上面流程
onActivityStopped->移除监听器
缺点:兼容性,无法采集dialog等点击事件
代理Window.Callback
当用户点击某个控件时,就会回调Window.Callback中的dispatchTouchEvent(MotionEvent event)方法。
onActivityCreated->获取Window.Callback->将callback进行包装->将包装callback设置到window
处理事件:
遍历decoreView->判断view是否在点击的坐标内->处理事件
缺点:无法采集dialog等点击事件,性能低,每次点击时,都需要去遍历一次RootView
代理View.AccessibilityDelegate
view->performClick->sendAccessibibltyEvent
反射获取view的AccessibilityDelegate->进行包装->回设给View
包装AccessibilityDelegate->重写sendAccessibibltyEvent->判断事件状态为点击->处理
缺点:辅助功能可能在部分rom会失效,反射效率低,无法采集dialog等点击事件
透明层
onActivityCreated->将透明层(FrameLayout)添加到decoreView
透明层->监听onTouchEvent->down->获取点击坐标范围的子view->处理->
return super.onTouchEvent(event) 确保透明层不会阻断事件
缺点:无法采集dialog等点击事件,性能低,每次点击时,都需要去遍历一次RootView
AspectJ
定义切面类->定义切点->方法增强@After 点击事件->joinPoint.getArgs获取到view->处理
缺点:不支持lambda,无法织入第三方的库,兼容性(D8、Gradle 4.x)
ASM
1.定义Transform类(项目构建阶段,修改.class文件的一套标准API),分别遍历目录和jar包进行过滤
2.在visit方法获取到class信息,visitMethod方法里获取到method信息
3.判断它所在的类实现了View.OnClickListener接口
4.在onMethodExit方法里进行判断,插入相关的代码。
缺点:目前无缺点
Javassist
·读写字节码
和ASM类似
AST
自定义注解处理器->初始化获取抽象语法树->遍历所有元素->如果类型为CLASS,获取当前元素的抽象语法树->
自定义TreeTranslator处理每一个方法->如果方法包含onclick就插入代码
缺点:无法处理其他module,不支持lambda