文档章节

Android自动埋点的一种实现

fneg
 fneg
发布于 2016/03/02 22:39
字数 664
阅读 1824
收藏 4
点赞 1
评论 2

在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

确认过眼神,这就是你要的路由库

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

浅吟且行的未来 ⋅ 05/31 ⋅ 0

Android插件化原理(一)Activity插件化

相关文章 Android深入四大组件系列 Android解析AMS系列 Android解析ClassLoader系列 前言 四大组件的插件化是插件化技术的核心知识点,而Activity插件化更是重中之重,Activity插件化主要有三...

刘望舒 ⋅ 05/29 ⋅ 0

Android 面试技能树梳理

相信大家都有面试的经历,相对比面试官的问的一些问题其实都是基础的知识,但就是一些基础的知识我们也不是很完美的回答出来,我们也知道现在的开发人员很多,一家公司一个岗位就会有很多的开...

liu3364575 ⋅ 05/05 ⋅ 0

Android埋点技术分析

Android埋点技术分析 Uncle Chen2017-12-271 阅读 技术AndroidSDK 一、概念 埋点,是对网站、App或者后台等应用程序进行数据采集的一种方法。通过埋点,可以收集用户在应用中的产生行为,进而...

Uncle Chen ⋅ 2017/12/27 ⋅ 0

Android应用开发以及设计思想深度剖析(3)

特别声明:本系列文章LiAnLab.org著作权所有,转载请注明出处。作者系LiAnLab.org资深Android技术顾问吴赫老师。 我们接下来从安全性,性能,功能,可移植性的角度分别分析Android系统为应用...

21cnbao ⋅ 2012/09/14 ⋅ 0

不需要再手写 onSaveInstanceState 了,因为你的时间非常值钱

  如果你是一个有经验的 Android 程序员,那么你肯定手写过许多 以及 方法用来保持 Activity 的状态,因为 Activity 在变为不可见以后,系统随时可能把它回收用来释放内存。重写 Activity...

Android群英传 ⋅ 今天 ⋅ 0

Android组件化之代码隔离插件

问题 在组件化的时候我发现遇到这些问题 组件可以访问其他组件所有Public的类,代码不内聚 组件依赖传递导致API向下不兼容会崩溃 API方法手动写在MarkDown 模块之间互相依赖会照成循环依赖无...

sunshine8 ⋅ 04/24 ⋅ 0

读书笔记--Android Gradle权威指南(上)

最近看了一本书《Android Gradle 权威指南》,对于 Gradle 理解又更深了,但不想过段时间就又忘光了,所以打算写一篇读书笔记,将书中一些我个人觉得蛮有用的点记录、总结一下。 前言 首先,...

请叫我大苏 ⋅ 05/24 ⋅ 0

加密传输才是王道!谷歌在 Android P 上默认启用 TLS

上周四谷歌表示,为保证用户数据和设备的安全,针对下一代 Android 系统(Android P) 的应用程序,将要求默认使用加密连接,这意味着 Android P 将禁止 App 使用所有未加密的连接,因此运行 ...

局长 ⋅ 04/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

【elasticsearch】 随笔 Date datatype

一。时间类型的本质 首先json是没有时间类型的,对于es来说,时间类型的标示可以是下面三种情况 1.一个时间格式的字符串,如:"2014-11-27T08:05:32Z","2015-01-01" or "2015/01/01 12:10:3...

xiaomin0322 ⋅ 26分钟前 ⋅ 0

阿里云资源编排ROS使用教程

阿里云资源编排ROS详细内容: 阿里云资源编排ROS使用教程 资源编排(Resource Orchestration)是一种简单易用的云计算资源管理和自动化运维服务。用户通过模板描述多个云计算资源的依赖关系、...

mcy0425 ⋅ 28分钟前 ⋅ 0

适配器设计模式

1、适配器模式 把一个类的接口变换成客户端所期待的另一种接口 使原本因接口不匹配而无法在一起工作的两个类能够在一起工作 分为类的适配器模式和对象的适配器模式 2、类适配器模式 类的适配...

职业搬砖20年 ⋅ 32分钟前 ⋅ 0

npm操作报错 _stream_writable.js:61

有一天 不知道什么原因(估计和node的版本有关),无论你做什么npm的操作 都会报错/usr/local/lib/node_modules/npm/node_modules/readable-stream/lib/_stream_writable.js:61 这时候只要执...

lilugirl ⋅ 36分钟前 ⋅ 0

Eclipse安装插件的几种方式

Eclipse魅力之一就是支持可扩展的插件,来丰富自身的功能,这种方式也是建立在开源思想之上的。具体使用什么方式去安装插件,要看我们拿到的是什么。 1. 拿到的是一串URL,如http://subclips...

GordonNemo ⋅ 39分钟前 ⋅ 0

div图片叠加

css实现代码如下: <div style="position: relative;"><!--这个层为外面的父层,需设置相对位置样式--> <div style="position: absolute;"><!--子层,需设置绝对位置样式--> <i......

niithub ⋅ 40分钟前 ⋅ 0

作用域slot

如果父组件需要使用子组件中的内容怎么办,比如父组件需要控制子组件的显示 <div id="root"><child><template slot-scope="props"><h1>{{props.item}} <div>编辑</div></h1><......

金于虎 ⋅ 43分钟前 ⋅ 1

HongHu commonservice-eureka 项目构建过程

上一篇我们回顾了关于 spring cloud eureka的相关基础知识,现在我们针对于HongHu cloud的eureka项目做以下构建,整个构建的过程很简单,我会将每一步都构建过程记录下来,希望可以帮助到大家...

明理萝 ⋅ 45分钟前 ⋅ 1

xml和对象的相互转化

@Data//setter和getter方法,toString和equals,hashcode方法@EqualsAndHashCode//代表重写equals和hashcode方法@XmlAccessorType(XmlAccessType.FIELD)public class Classroom {@X......

拐美人 ⋅ 46分钟前 ⋅ 0

tableView cell的高度 分组头部尾部的高度 自适应

@property (nonatomic) CGFloat rowHeight; // default is UITableViewAutomaticDimension@property (nonatomic) CGFloat sectionHeaderHeight; // default is UITableViewA......

娜一片蓝色星海 ⋅ 47分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部