一、背景

运营者能够对用户行为进行分析的前提,是对大量数据的掌握。在以往,这个数据通常是由开发者在控件点击、页面等事件中,一行行地编写埋点代码来完成数据收集的。然而传统的操作模式每当升级改版时,开发和测试人员就需要重复不断对代码进行更新,整个流程耗时长,无法满足业务的需求。

为帮助开发者解决这一痛点,个推应用统计“个数”推出“可视化埋点”这一技术来更高效地实现这个这一过程。“个数”的可视化埋点灵活、方便,开发者不需对数据追踪点添加任何代码,只需要连接管理台并圈选页面中需要埋点的元素,即可添加随时生效的界面追踪点。

本文将结合个数实践经验,对可视化埋点中的两大关键技术点即控件唯一标识和事件采集进行分析并提供解决方案。

二、可视化埋点关键技术点

可视化埋点的难点,或者说核心就是如何在开发者不编写任何代码的情况下,SDK 如何确定任意一个控件在该应用内的唯一性,以及如何监听控件的点击和页面的切换。

标识

为了防止不同页面中的控件标识重复出现,控件的唯一标识一般由页面标识加上控件标识生成。

页面标识生成

页面标识可以直接使用页面的名称,即 Activity name。其获取方式比较多,这里介绍一种比较通用的方法,即通过注册 Application.ActivityLifecycleCallbacks ,开发者可以在以下生命周期的回调中,轻松地拿到当前的 Activity 对象。此方法适用于一个 Activity 并无 Fragment 存在的情形。

代码详见下图:

获取方式也是比较多,不过较于 Activity 的获取会相对麻烦一些,因为系统没有直接提供 API ,因而需要稍微转个弯:通过 Gradle 插桩的方式,获取 Fragment 的生命周期,以及 Fragment 实例对象:

如果该应用的页面存在一个 Activity 中嵌套多个 Fragment 的情况,单单一个 Activity name则可能无法精准地定位到某个页面,因而还需要加上 Fragment 的名称。Fragment的获取可以通过 Gradle 插桩法来实现,即根据 Fragment 的生命周期来获取Fragment 实例对象。

1.2控件标识生成

理想的情况下页面中的每个控件都有属于自己的唯一 id,SDK 直接获取控件的 id 当做控件标识即可。但现实情况却是,一个页面中往往存在多个相同 id 的控件,或者是没有 id 的控件,比如 Listview 的 item ,开发者不可能给listview的每个item 设置不同的 id。

因此需要转变一下思路。我们可以从控件路径这个除id 外比较独特的性质着手来生成控件标识。开发者可以通过给控件的路径加上控件角标的结构方式,生成控件的唯一标识。下图是Github 上一个仿 B 站的应用。我们对这个应用进行一下控件树分析。首先我们使用 Android Studio 自带的 UI Automator Viewer 工具查看该页面的布局结构:

接下来,我们可以从Application.ActivityLifecycleCallbacks 的回调中拿到 Activity 实例,再使用 activity.getWindow().getDecorView().getRootView() 方法来获取当前页面的控件树。

例如图中的文字控件是 TextView,且无兄弟布局,则可以标记为 TextView[0] 。它的父布局是 LinearLayout 且排在兄弟布局中的第二位,那么就可以写成是 LinearLayout[1],然后使用自己定义的符号拼接,像是 LinearLayout[1]/TextView[0] 。之后以此类推、循环遍历、层层递进,将所有经过的控件以及它们的下标都拼接起来,组成控件在该页面中的唯一标识。

对于一些可复用的 View ,我们则需要采取一些特殊处理。例如对于 RecyclerView、ListView、 ViewPager 等复用控件,我们都需要采取不同的处理方式,去获取当前 View 在该控件中的具体下标。如果没有进行特殊处理,则会导致子控件错位,数据统计不准确。

采集

在以往的处理中,如果需要知道一个按钮的点击次数,开发者就要在该控件的click事件中加入对应的打点代码。这种重复劳作,无疑增加了开发者的开发负担。对此,我们可以采用动态代理方式或Gradle 插桩方式来改善这个问题。

动态代理方式

使用安卓自带的辅助功能 View.AccessibilityDelegate 。前文提到当页面变化时,我们可以通过 Application.ActivityLifecycleCallbacks 获取到 Activity 的实例对象,接着根据activity.getWindow().getDecorView().getRootView() 来获取到控件树。由于控件树可能会实时发生变化,我们则需要通过 ViewTreeObserver.OnGlobalLayoutListener 的方法监听视图变化,从而在该回调中拿到变化的控件。接着我们 要根据递归判断该控件是否为 ViewGroup、是否可以点击、是否能够显示等,继而给符合条件的 View 设置 sendAccessibilityEvent();此外,我们还要在继承了 View.AccessibilityDelegate 的定义类中,对以下这些方法添加 SDK 的代理:

当对应的控件被点击时,系统就会自动调用设置过代理的方法,存储或者上报对应数据。

Gradle 插桩的方式

Android Gradle 工具在1.5.0 版本后提供了 Transfrom API , 该API 允许第三方 Plugin 在打包 dex 文件之前的编译过程中操作 .class 文件。在编译期,开发者可以通过onClick、onItemClick等方法(详见下图)进行监听,这相当于是正则匹配。

当上述监听的方法被编译的时候,就可以将埋点的代理操作插入这些方法中,实现自动化埋点的流程。网上相关流程也是非常详细,有兴趣的可以自行搜索学习。

三、结语

以上就是APP端可视化埋点实现过程中的关键点,特别需要注意的是控件唯一标识那一块,由于布局千变万化,开发者针对很多特定的布局都需要采取对应的处理方式。

目前个推应用统计——个数这个产品只需要一行初始化代码就可以自动帮助开发者采集包括页面统计、事件埋点、新增活跃等多维度信息。

借着万圣节,悄悄跟你说个恐怖的故事:除个推应用统计服务之外,VIP消息推送、用户画像,现在申请均可以免费用一年!一键认证服务还可以享受充10万条送5万条的优惠哦 !点击https://www.getui.com/2019devfest,“码“上申请吧!

行业前沿、面试宝典,更多技术干货,尽在个推技术学院。

App可视化埋点技术原理大揭秘的更多相关文章

  1. 诗人般的机器学习,ML工作原理大揭秘

    诗人般的机器学习,ML工作原理大揭秘 https://mp.weixin.qq.com/s/7N96aPAM_M6t0rV0yMLKbg 选自arXiv 作者:Cassie Kozyrkov 机器之心 ...

  2. 不要再被骗了------QQ盗号原理大揭秘

    前言 相信大家在懵懂无知的时候都有被盗号的经历吧,QQ胡乱的加好友,突然有个好友传了个文件给你,打开以后发现QQ竟然显示强制下线,然后再也上不去了QAQ,很明显,QQ号被人盗了.最近也是很多小伙伴私信 ...

  3. AsyncTaskLoader设计原理大揭秘

    简介 在Android异步处理之AsyncTaskLoader简单使用中我简单的介绍了一下AsyncTaskLoader的基本用法和使用场景,对AsyncTaskLoader还不是很熟悉的小伙伴可以先 ...

  4. Protocol Buffer 序列化原理大揭秘 - 为什么Protocol Buffer性能这么好?

    前言 习惯用 Json.XML 数据存储格式的你们,相信大多都没听过Protocol Buffer Protocol Buffer 其实 是 Google出品的一种轻量 & 高效的结构化数据存 ...

  5. Android埋点技术分析

    1.现有的几种埋点技术的实现原理和优劣分析 (1)代码埋点:将收集数据的代码直接写在需要的地方,当用户点击某个控件或者打开某个页面时调用到该部分代码完成数据的收集. 优势:准确性高,收集数据和发送数据 ...

  6. 【腾讯Bugly干货分享】iOS黑客技术大揭秘

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5791da152168f2690e72daa4 “8小时内拼工作,8小时外拼成长 ...

  7. 大数据基础总结---MapReduce和YARN技术原理

    Map Reduce和YARN技术原理 学习目标 熟悉MapReduce和YARN是什么 掌握MapReduce使用的场景及其原理 掌握MapReduce和YARN功能与架构 熟悉YARN的新特性 M ...

  8. 【高德地图API】汇润做爱地图技术大揭秘

    原文:[高德地图API]汇润做爱地图技术大揭秘 昨日收到了高德地图微信公众号的消息推送,说有[一大波免费情趣用品正在袭来],点进去看了一眼,说一个电商公司(估计是卖情趣用品的)用高德云图制作了一张可以 ...

  9. 基于日志服务的GrowthHacking(1):数据埋点和采集(APP、Web、邮件、短信、二维码埋点技术)

    数据质量决定运营分析的质量 在上文中,我们介绍了GrowthHacking的整体架构,其中数据采集是整个数据分析的基础,只有有了数据,才能进行有价值的分析:只有高质量的数据,才能驱动高质量的运营分析. ...

随机推荐

  1. 求问:numpy里面索引时,采用整型数组和整型列表的区别!

  2. 从尾到头打印列表——牛客剑指offer

    题目描述 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. 解题思路 思路1: 顺序遍历链表,取出每个结点的数据,插入list中. 由于要求list倒序存储链表中的数据,而我们是顺序取 ...

  3. leetcode 1266. Minimum Time Visiting All Points

    On a plane there are n points with integer coordinates points[i] = [xi, yi]. Your task is to find th ...

  4. Vue 路由拦截(对某些页面需要登陆才能访问)

    前言 做项目的时候有个需求,就是发现没有登录,竟然也可以进入我的主页,这样肯定是不能容忍的.于是就要让他进入主页的时候,加个判断是否有登录,若没有登录,则返回登录界面,登录成功后还可以跳转到之前进入的 ...

  5. 多Y轴,下拉框渲染,相同类型不同数据

    放上json文件: { "2017年3月": { "outKou": "5525.86", "inKou": " ...

  6. html2canvas+Canvas2Image分享海报功能踩坑

    首先需要 import html2canvas from 'html2canvas'; import {Canvas2Image} from '../../assets/js/plug/canvas2 ...

  7. appium 自动化测试框架详读(一)

    appium框架使用的过程记录,开始使用markdown来语法来编写,不知道博客园是否会支持markdown语法 ***1. appium原理* appium启动时,创建一个http://127.0. ...

  8. hashmap的hash方法源doc解读

    /** * Computes key.hashCode() and spreads (XORs) higher bits of hash * to lower. Because the table u ...

  9. python 读excel表操作

    import xlrd # 打开文件 data = xlrd.open_workbook('测试表.xlsx') # 查看工作表 data.sheet_names() print("shee ...

  10. linux 静态路由

    用ip route删除默认路由 ip route del default via 192.168.18.1 用route删除默认路由route del default gw 192.168.18.1 ...