Android 可视化埋点方案

Android 可视化埋点方案,第1张

概述背景目前统计打点已经是一个产品常见的需求,尤其在业务模式探索的前期,埋点功能更是必不可少的功能,下面将介绍最简单的app全埋点方案!什么是数据埋点数据埋点是一般项目采用统计UV,PV,Action,Time等一系列的数据信息,对特定用户行为或事件进行捕获、处理和发送的相关技术及其实施过程。为 背景

目前统计打点已经是一个产品常见的需求,尤其在业务模式探索的前期,埋点功能更是必不可少的功能,下面将介绍最简单的app全埋点方案!

什么是数据埋点

数据埋点是一般项目采用统计UV,PV,Action,Time等一系列的数据信息,对特定用户行为或事件进行捕获、处理和发送的相关技术及其实施过程。

为什么要数据埋点

产品或运营分析人员,基于埋点数据分析需要,对用户行为的每一个事件进行埋点布置,并通过SDK上报埋点的数据结果,进行分析,并进一步优化产品或指导运营。
数据埋点包括哪些
这里有我之前写的一篇文章App优质精准的用户行为统计和日志打捞方案
地址:blog.csdn.net/sk719887916…

数据埋点采集模式

自动埋点
App通过代理,调用Sdk相关API,进行的将数据埋点上报的模式.
无痕埋点
无需通过专门提供代理类,直接由sdk提供相关接口,或者通过编译工具,预编译替换代码等,直接由sdk全部负责采集上报
可视化埋点
可视化埋点指 前端或者app端基于dom 元素和控件所精准自动埋点的上报的方案。

对比分析:

自动埋点:
缺点:
1 开发人员工作量大,需对业务提供唯一的ID,来区分每一个业务,无论是否提供sdk代理,业务开发人员至少需要多次调用sdk相关API.
2  业务人员和产品沟通成本提高,需要对具体业务制定相关的业务标识,以便于产品分析和统计
优点:
产品运营工作量少,对照业务映射表,就能分析出还原相关业务场景, 数据比较精细,无需大量的加工和处理。


无痕埋点
缺点:
1 sdk开发人员需提供一套无痕埋点技术成品,包括能正确获取PV,UV,ACtion,TIme等多项统计指标。前期技术投入大。
2 数据量大,需后端落地进行大量处理,并由产品进行自我还原业务员场景。 无论采用智能系统平台,还是通过原生的数据库查询数据,都是一种大量的分析精力。
优点:
1 开发人员工作量小,无需对业务标识进行唯一区分,由sdk自动进行生成,ID规则由sdk和产品进行约定。减少业务人员的沟通成本和使用步骤。
2 数据量全面,覆盖面广,产品可按需进行分析。做到毫无遗漏。
3 支持动态页面和局部动效的统计。


可视化埋点
优点:
1 相对数据量而言
相比较于无埋点相而言对较低,但是这个可视化元素的识别技术是客户端或者前端所要实现的,唯一ID生成也无需客户端去自定义规则,这套生成规则由相关产品在自动化工具的情况下生成配置表,下发到客户端,再由客户端按坑就班到相关界面去实现。
2 数据量相对精确
缺点:
1 可视化工具的平台的搭建,静态页面的元素识别都需要额外开发。
2 动态效果可能会遗漏。

实现方案:

埋点需求可参考我之前的文章:
App优质精准的用户行为统计和日志打捞方案:https://blog.csdn.net/sk719887916/article/details/50931485
App打造自定义的统计SDK:
https://www.jianshu.com/p/cd83e81b78aa
自动埋点实际上也是,提供一个base类,由业务类继承base类,在base里面做相关统计API调用,
可参考我的github:github.com/Tamicer/Sky…

打点要素

androID端打点的四个要素


1 vIEw展现,点击,消失
AccessibilityDelegate.
AccessibilityDelegate的使用(API level 14)
AccessibilityDelegate主要用来对vIEw做一个检测,包括vIEw的点击,选中,滑动,touch,文本变化及描述等等,可以用来做一些数据统计或者分析
创建一个自定义的AccessibilityDelegate,实现sendAccessibilityEvent(VIEw host, int eventType)方法,然后通过vIEw.setAccessibilityDelegate(),当该vIEw的相关属性出现变化时,就会回调到实现的sendAccessibilityEvent方法中,我们可以通过AccessibilityEvent.type_xxx来区分eventType是什么类型,然后做不同的处理
给VIEw设置AccessibilityDelegate,而当VIEw 产生了click,long_click 等事件的时候.会在响应原有的Listener方法后.发送消息给
AccessibilityDelegate.然后在sendAccessibilityEvent方法下做打点 *** 作.


2 页面监听
ActivitylifecycleCallbacks
application.registeractivitylifecycleCallbacks(new Application.ActivitylifecycleCallbacks() {}
在onResume中对activity.getwindow().getDecorVIEw().getRootVIEw()进行向下遍历


3 定位VIEw
VIEw 的唯一性.
根据context的classname+VIEw自身的 ID的String 值.(String 值可以反射R文件得到)+VIEw 的classname值确定.
当前没有ID.向上需要父类的ID,如果父类ID 没有则记录父类classname+getChildAt()值并且继续往上找,直到找到有ID的vIEw或者没有父类为止


4 上报时机
启动上报 轮询上报,网络变化,前后台切换,主动上报,推送回捞

核心实现:

以AndroID作为列子:
提供自动遍历元素 并能扑捉点击的控件的activity, 并能在生命周期统计pv的打开和关闭,调用我开源的SkyMonitoring的对应的API.
复写dispatchtouchEvent(MotionEvent ev) 事件函数,确定被点击的vIEw的相关位置,并生成唯一的ID,企业级app都是从服务器下发对应的ID,对应页面去调用埋点sdk API,实现事件行为TcStatInterface.initEvent(path.vIEwTree);。
这个path就是vIEw的路径,页面的深度路径,包括打开和关闭sdk在SkyMonitoring中已能自动获取。
本次demo是ID生成规则是按照 :包名+ Activity+ VIEwgroup+ Layout+ vIEw + VIEw index + vIEwID实现的。
业务直接去继承TamicActivity即可,就能去实现所有可视化vIEw的埋点功能。
代码如下:

   public abstract class TamicActivity extends AppCompatActivity {


    private int statusbarHeight;
    VIEw rootVIEw;
    String rootVIEwTree;
    String bigDataPrefix;
    String bigDataIngorePrefix;
    String bigDataEventPrefix;
    private String TAG  = "LYK";

    @OverrIDe
    public voID onAttachedToWindow() {
        super.onAttachedToWindow();
        //获取到根节点的vIEw
        rootVIEw = getwindow().getDecorVIEw();
        //控件在视图树上的根路径
        rootVIEwTree = getPackagename() + "." + getClass().getSimplename();
        //前缀名 bigData
        bigDataPrefix = "Tamic_test";
        //前缀名 bigData_
        bigDataIngorePrefix = bigDataPrefix + "";
        //前缀名 bigdata_ignore
        bigDataEventPrefix =  bigDataIngorePrefix +"Igmore";
    }

    @OverrIDe
    protected voID onResume() {
        super.onResume();

        TcStatInterface.recordPageStart(TamicActivity.this);
    }

    @OverrIDe
    protected voID onPause() {
        super.onPause();

        TcStatInterface.recordPageEnd();
    }

    @OverrIDe
    protected voID onDestroy() {
        super.onDestroy();
        // APP退出
        TcStatInterface.recordAppEnd();

    }


    @OverrIDe
    public boolean dispatchtouchEvent(MotionEvent ev) {

        if(ev.getAction() == MotionEvent.ACTION_DOWN){
            VIEwPath path = findClickVIEw(ev);
            if(path != null) {
                Log.e(TAG, "path -->" + path.vIEwTree);
                TcStatInterface.initEvent(path.vIEwTree);
            }
        }
        return super.dispatchtouchEvent(ev);
    }

    private VIEwPath findClickVIEw(MotionEvent ev) {
        Log.e(TAG, "bigdata-->findClickVIEw");
        VIEwPath clickVIEw = new VIEwPath(rootVIEw, rootVIEwTree);
        return searchClickVIEw(clickVIEw, ev, 0);
    }


    private VIEwPath searchClickVIEw(VIEwPath myVIEw, MotionEvent event, int index) {
        VIEwPath clickVIEw = null;
        VIEw vIEw = myVIEw.vIEw;
        if (isInVIEw(vIEw, event)) {   
            myVIEw.leveL++;
            if (myVIEw.level == 2 && !"linearLayout".equals(vIEw.getClass().getSimplename())) {
                myVIEw.filterLevelCount++;
            }
            if (myVIEw.level > myVIEw.filterLevelCount) {
                myVIEw.vIEwTree = myVIEw.vIEwTree + "." + vIEw.getClass().getSimplename() + "[" + index + "]";
            }
            Log.i(TAG, "bigdata-->tag = " + vIEw.getTag());
            if (vIEw.getTag() != null) {
                // 主动标记不需要统计时,不进行自动统计
                String tag = vIEw.getTag().toString();
                if (tag.startsWith(bigDataIngorePrefix)) {
                    return null;
                } else if (tag.startsWith(bigDataPrefix)) {
                    if (tag.startsWith(bigDataEventPrefix)) {
                        myVIEw.specifyTag = tag.replace(bigDataEventPrefix, "");
                    }
                    return myVIEw;
                }
            }
            if (vIEw instanceof VIEwGroup) {   
                if (vIEw instanceof AbsListVIEw) {
                    Log.i(TAG, "bigdata-->AbsListVIEw ");
                    return null;
                }
                VIEwGroup group = (VIEwGroup) vIEw;
                int childCount = group.getChildCount();
                if (childCount == 0) {
                    return myVIEw;
                }
                for (int i = childCount - 1; i >= 0; i--) {
                    myVIEw.vIEw = group.getChildAt(i);
                    clickVIEw = searchClickVIEw(myVIEw, event, i);
                    if (clickVIEw != null) {
                        return clickVIEw;
                    }
                }
            } else {
                clickVIEw = myVIEw;
            }
        }
        return clickVIEw;
    }

    private boolean isInVIEw(VIEw vIEw, MotionEvent event) {
        if (vIEw == null || vIEw.getVisibility() != VIEw.VISIBLE) {
            return false;
        }
        int clickX = (int) event.getRawX();
        int clickY = (int) event.getRawY();
        int[] location = new int[2];
        vIEw.getLocationOnScreen(location);
        int x = location[0];
        int y = location[1];
        int wIDth = vIEw.getWIDth();
        int height = vIEw.getHeight();
        return clickX > x && clickX < (x + wIDth) && clickY > y && clickY < (y + height);
    }
   }

App项目集成使用,初始化url和相关统计配置字典,这个字典可以从服务器下发下来,我本次只是通过简单的本地文件做实践。

public class StatAppliation extends Application {

@OverrIDe
public voID onCreate() {
    super.onCreate();
    // you app ID
    int appID = 21212;
    // assets
    String filename = "my_statconfig.Json";
    String url = "https://github.com/Tamicer/TamicAppMonitoring";
    // init statSdk
    TcStatInterface.initialize(this, appID, "you app chanel", filename);
    TcStatInterface.setUrl(url);
    TcStatInterface.setUploadPolicy(TcStatInterface.UploadPolicy.UPLOAD_POliCY_DEVELOPMENT, TcStatInterface.UPLOAD_TIME_ONE);
 }
}

可视化也可以通过aop插桩实现,但是实现起来对代码的***性太高,这里不做介绍。
aop插桩对碎片化fragment支持比较好。对这块的介绍可看我以前在公众号推送的一篇文章:AOP编程之AspectJ实战实现数据无痕埋点

可参考:
https://www.baIDu.com/link?url=FniQOFyj1pd6O5Fz6viRMN3ZgexIKAk7SQ08EgpBU9cHHMszPlm2jRXJ21mkomtY&wd=&eqID=ffc87acf0005fd18000000045a5d98dd

项目地址:

https://github.com/Tamicer/TamicAppMonitoring

总结

以上是内存溢出为你收集整理的Android 可视化埋点方案全部内容,希望文章能够帮你解决Android 可视化埋点方案所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1049814.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)