1、背景面试
运营者可以对用户行为进行分析的前提,是对大量数据的掌握。在以往,这个数据一般是由开发者在控件点击、页面等事件中,一行行地编写埋点代码来完成数据收集的。然而传统的操做模式每当升级改版时,开发和测试人员就须要重复不断对代码进行更新,整个流程耗时长,没法知足业务的需求。工具
为帮助开发者解决这一痛点,个推应用统计“个数”推出“可视化埋点”这一技术来更高效地实现这个这一过程。“个数”的可视化埋点灵活、方便,开发者不需对数据追踪点添加任何代码,只须要链接管理台并圈选页面中须要埋点的元素,便可添加随时生效的界面追踪点。布局
本文将结合个数实践经验,对可视化埋点中的两大关键技术点即控件惟一标识和事件采集进行分析并提供解决方案。学习
2、可视化埋点关键技术点测试
可视化埋点的难点,或者说核心就是如何在开发者不编写任何代码的状况下,SDK 如何肯定任意一个控件在该应用内的惟一性,以及如何监听控件的点击和页面的切换。ui
标识3d
为了防止不一样页面中的控件标识重复出现,控件的惟一标识通常由页面标识加上控件标识生成。代理
页面标识生成server
页面标识能够直接使用页面的名称,即 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等方法(详见下图)进行监听,这至关因而正则匹配。
当上述监听的方法被编译的时候,就能够将埋点的代理操做插入这些方法中,实现自动化埋点的流程。网上相关流程也是很是详细,有兴趣的能够自行搜索学习。
3、结语
以上就是APP端可视化埋点实现过程当中的关键点,特别须要注意的是控件惟一标识那一块,因为布局变幻无穷,开发者针对不少特定的布局都须要采起对应的处理方式。
目前个推应用统计——个数这个产品只须要一行初始化代码就能够自动帮助开发者采集包括页面统计、事件埋点、新增活跃等多维度信息。
借着万圣节,悄悄跟你说个恐怖的故事:除个推应用统计服务以外,VIP消息推送、用户画像,如今申请都可以避免费用一年!一键认证服务还能够享受充10万条送5万条的优惠哦 !点击https://www.getui.com/2019devfest,“码“上申请吧!
行业前沿、面试宝典,更多技术干货,尽在个推技术学院。