Android 全埋点解决方案 (11):AppStartAppEnd 全埋点方案 3.1

阅读数:6 2019 年 11 月 30 日 22:55

Android全埋点解决方案(11):$AppStart、$AppEnd全埋点方案 3.1

(原理概述)

内容简介
这是一本实战为导向的、翔实的 Android 全埋点技术与解决方案手册,是国内知名大数据公司神策数据在该领域多年实践经验的总结。由神策数据合肥研发中心负责人亲自执笔,他在 Android 领域有近 10 年研发经验,开发和维护着知名的商用开源 Android & iOS 数据埋点 SDK。
本书详细阐述了 Android 全埋点的 8 种解决方案,涵盖各种场景,从 0 到 1 详解技术原理和实现步骤,并且提供完整的源代码,各级研发工程师均可借此实现全埋点数据采集,为市场解开全埋点的神秘面纱。
8 种 Android 全埋点解决方案包括:
AppClick 全埋点方案 1:代理 View.OnClickListener、
AppClick 全埋点方案 2:代理 Window.Callback
AppClick 全埋点方案 3:代理 View.AccessibilityDelegate
AppClick 全埋点方案 4:透明层
AppClick 全埋点方案 5:AspectJ
AppClick 全埋点方案 6:ASM
AppClick 全埋点方案 7:Javassist
AppClick 全埋点方案 8:AST

针对上面列出的 3 个问题,我们下面将一一进行分析并解决。

(1)应用程序如果有多个进程该如何判断是处于前台还是处于后台?

众所周知,一个 Android 应用程序是可以有多个进程同时存在的,所以这就加大了我们判断一个应用程序是处于前台还是处于后台的难度,继而导致很多常见的判断方案也都会失效。

其实,对于这个问题,可以归于应用程序多进程间的数据共享问题。

Android 系统中支持多进程通信方式主要有以下几种,它们各有优缺点。

  • AIDL

AIDL 的功能相对来说比较强大,支持进程间一对多的实时并发通信,并且可以实现 RPC(远程过程调用)。

  • Messenger

Messenger 支持一对多的串行实时通信,它相当于是 AIDL 的简化版本。

  • Bundle

Bundle 是 Android 系统中四大组件的进程间通信方式,目前只能传输 Bundle 支持的数据类型,比如 String、int 等。

  • ContentProvider

ContentProvider 是一个非常强大的数据源访问组件,主要支持 CRUD 操作和一对多的进程间数据共享,例如我们的应用访问系统的图库数据。

  • BroadcastReceiver

BroadcastReceiver 即广播,目前只能支持单向通信,接收者只能被动地接收消息。

  • 文件共享

文件共享主要适用于在非高并发情况下共享一些比较简单的数据。

  • Socket

Socket 主要通过网络传输数据。

我们目前的方案主要是采用 ContentProvider 机制来解决进程间的数据共享问题。ContentProvider 是基于 Binder 机制封装的系统组件,天生就是用来解决跨进程间的数据共享问题的。另一方面,Android 系统也提供了针对 ContentProvider 的数据回调监听机制—即 ContentObserver,这样就更加方便我们来处理跨进程间的数据通信方面的问题。

一般情况下,解决跨进程数据共享的问题,普遍采用的是 ContentProvider + SQLite3 方案,但是鉴于目前我们面临的实际情况,使用 SQLite3 数据库来存储一些简单的数据和标记位,明显太过重量级了。通常在 Android 系统以及应用程序开发中,针对一些比较简单的数据的存储,一般采用 SharedPreferences,从而可以做到快速读写。所以我们目前采用“ContentProvider + SharedPreferences”的方案来解决跨进程数据共享的问题。

(2)应用程序如果发生崩溃或者被强杀了该如何判断该应用程序是处于前台还是处于后台?

对于应用程序发生崩溃或者应用进程被强杀的场景,我们引入了 Session 的概念。简单理解就是:对于一个应用程序,当它的一个页面退出了,如果在 30s 之内没有新的页面打开,我们就认为这个应用程序处于后台了(触发 AppEnd退30sAppStart 事件)。此时,Session 的间隔我们是以 30s 为例。

总体来说,我们首先注册一个 Application.ActivityLifecycleCallbacks 回调,用来监听应用程序内所有 Activity 的生命周期。然后我们再分两种情况分别进行处理。

在页面退出的时候(即 onPause 生命周期函数),我们会启动一个 30s 的倒计时,如果 30s 之内没有新的页面进来(或显示),则触发 AppEndActivityActivityandroid:processContentProvider+SharedPreferencesContentObserver退30sHome/退AppEnd 事件,或者在下次启动的时候补发一个 AppEndAppEnd 事件,是因为对于一些特殊的情况(应用程序发生崩溃、应用程序被强杀),应用程序可能停止运行了,导致我们无法及时触发 AppEndAppEnd 事件。

在页面启动的时候(即 onStart 生命周期函数),我们需要判断一下与上个页面的退出时间间隔是否超过了 30s,如果没有超过 30s,则直接触发 AppViewScreen30sAppEnd 事件(因为如果 App 崩溃了或者被强杀了,可能没有触发 AppEndAppEnd 事件,然后再触发 AppStartAppViewScreen 事件。

Android全埋点解决方案(11):$AppStart、$AppEnd全埋点方案 3.1

购书地址 https://item.jd.com/12574672.html?dist=jd

评论

发布