文档章节

Android自动埋点的一种实现

fneg
 fneg
发布于 2016/03/02 22:39
字数 664
阅读 1893
收藏 4

在App开发过程中,埋点都要花费很多时间,而且还有遗漏没有埋的情况,能不能做到服务器下发哪些控件要埋,然后客户端自动埋。 前几天想出来了一个方案,今天实现了一个Demo,大概过程就是:遍历界面上所有View --> 如果View设置了OnClickListener,并且View的ID在配置文件中,那就替换OnClickListener为DelegentOnClickListener -->DelegentOnClickListener先调用埋点,然后再调用原先View的ClickListener。 

1.首先获取到控件的OnClickListener,Android 系统中没有相对应的API,查看View的源码,发现可以通过反射的方式获取到,Android系统将View相关Listener放到了一个内部类ListenerInfo中,从View 的mListenerInfo中可以获取到OnClickListener,大概的代码是这样的:

private View.OnClickListener getOnClickListener(View view) {
    boolean hasOnClick = view.hasOnClickListeners();
    if (hasOnClick) {
        try {
            Method method = View.class.getDeclaredMethod("getListenerInfo", null);
            if (null != method) {
                method.setAccessible(true);
                Object object = method.invoke(view, new Object[]{});
                if (null != object) {
                    Class listenerInfoClazz = object.getClass();
                    Field mOnClickListener = listenerInfoClazz.getDeclaredField("mOnClickListener");
                    if (null != mOnClickListener) {
                        mOnClickListener.setAccessible(true);
                        Object listener = mOnClickListener.get(object);
                        if (null != listener && listener instanceof View.OnClickListener) {
                            return (View.OnClickListener) listener;
                        }
                    }
                }
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
    return null;
}

2.遍历界面中的所有View,然后替换在配置文件中的View的OnClickListener,实现代码:

private void setClickListener(final View view) {
    if (null != view) {
        boolean hasOnClick = view.hasOnClickListeners();
        if (hasOnClick) {
            final View.OnClickListener listener = getOnClickListener(view);
            int id = view.getId();
            String name = getResources().getResourceName(id);
            //AdapterView不能设置OnClickListener
            if (!(view instanceof AdapterView)) {
                //检查是否在配置文件中,请求OnClickListener没替换过
                if (!(listener instanceof DelegentOnClickListener) &&
                        mTraceManager.isNeedTrace(this.getClass().getName(), name)) {
                    view.setOnClickListener(new DelegentOnClickListener() {
                        @Override
                        public void onClick(View v) {
                            Log.e(TAG, "new clickListener");
                            if (null != listener) {
                                listener.onClick(v);
                            }
                            Log.e(TAG, v.getTag(v.getId()) + "");
                        }
                    });
                }
            }
        }
        if (view instanceof ViewGroup) {
            final ViewGroup viewGroup = (ViewGroup) view;
            int childCount = viewGroup.getChildCount();
            if (childCount > 0) {
                for (int i = 0; i < childCount; i++) {
                    View childView = viewGroup.getChildAt(i);
                    setClickListener(childView);
                }
            }
        }
    }

}

3.替换界面中所有的View的OnClickListener,实现代码: setClickListener(findViewById(android.R.id.content));

4.在Assets的配置文件中添加要追踪的Activity和View id。 这个Demo实现了大概的原理验证,距离真实的产品,还有很大的距离,包括替换所有View的OnClickListener的时机怎么选择,ListView,RecycleView的Item监听,还有OnTouchListenr,OnLongClickListener实现,通过设置DelegentTouchListener应该还可以实现界面的热力图,配置文件可以从服务器端下发,做到动态埋点,View可以有意识的setTag(id,object),然后埋点反序列化这个object,可以做到埋入一些参数信息,配置文件还可以扩展一下,有控件名称之类的。 配图很梦幻,如果实现了自动埋点,对运营和开发来说也是梦幻的。  

项目地址:https://github.com/fengcunhan/AutoTrace 


© 著作权归作者所有

共有 人打赏支持
fneg

fneg

粉丝 76
博文 43
码字总数 23812
作品 0
杭州
高级程序员
加载中

评论(2)

本人慧星撞地球
本人慧星撞地球

引用来自“PREPOET”的评论

https://github.com/mixpanel/mixpanel-android 有开源的埋点SDK,利用setAccessibilityDelegate

回复@PREPOET : 大哥这东西怎么用啊,能拿过来直接用吗?等待您的答复
PREPOET
PREPOET
https://github.com/mixpanel/mixpanel-android 有开源的埋点SDK,利用setAccessibilityDelegate
使用Kotlin高效地开发Android App(二)

继上一篇文章介绍了项目中所使用的Kotlin特性,本文继续整理当前项目所用到的特性。 一.apply 函数 和 run 函数 with、apply、run函数都是Kotlin标准库中的函数。with在第一篇文章中已经介绍...

Tony沈哲
04/27
0
0
Android自动化页面测速在美团的实践

背景 随着移动互联网的快速发展,移动应用越来越注重用户体验。美团技术团队在开发过程中也非常注重提升移动应用的整体质量,其中很重要的一项内容就是页面的加载速度。如果发生冷启动时间过...

美团技术团队
07/17
0
0
确认过眼神,这就是你要的路由库

上一篇文章我们谈到了如何实现一个路由库,那本篇文章就给大家推荐一个好用的路由库,来确认下眼神,这就是你要的路由库。 EasyRouter:一个简单、稳定、强大、高性能的组件化路由框架。git...

浅吟且行的未来
05/31
0
0
Android 自定义进度条(指示器)

进度条分类 Android中进度条控件有3个(不算ProgressDialog),分别是ProgressBar、SeekBar和RatingBar,对于自定义样式来说又得按照需求分为2中情况,第一种是刻度型,第二种是循环类型。 ...

IamOkay
2014/12/14
0
4
android同时监听所有activity生命周期状态实现

在做应用统计时我们可能需要在获取activity的生命周期状态,以前的方式是我们需要重写每一个activity的onResume() 等函数然后埋点。现在可以利用apkplug框架的activitylifecycle将所有activ...

梁大帅
2014/04/30
0
3

没有更多内容

加载失败,请刷新页面

加载更多

下一页

(三)Nginx配置·续

概述 前文写了关于Nginx环境配置,但是还没有完,接下来将会继续讲三个相关的配置 主要是以下三个 1.Nginx访问日志 2.Nginx日志切割 3.静态文件不记录日志和过期时间 Nginx访问日志 1.先看看...

杉下
今天
1
0
jquery创建类似于java的map

var map = {}; // Map map = new HashMap(); map[key] = value; // map.put(key, value); var value = map[key]; // Object value = map.get(key); var has = key in map; // boolean has = ......

SuperDabai
今天
0
0
java大数据转换16进制转10进制

public static void main(String[] args) {String hex = "0xdbf3accc683297cf0000";BigInteger amount = new BigInteger(hex.substring(2), 16);System.out.println(amount);......

任梁荣
昨天
2
0
OSChina 周六乱弹 —— 目测我们程序员丁克的几率不大

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @真Skr小机灵鬼儿:8.13分享Jocelyn Pook/Russian Red的单曲《Loving Strangers》 《Loving Strangers》- Jocelyn Pook/Russian Red 手机党少...

小小编辑
昨天
15
4
TypeScript基础入门 - 函数 - 剩余参数

转载 TypeScript基础入门 - 函数 - 剩余参数 项目实践仓库 https://github.com/durban89/typescript_demo.gittag: 1.2.1 为了保证后面的学习演示需要安装下ts-node,这样后面的每个操作都能...

durban
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部