countly-sdk-android

用户行为分析开源框架(埋点)
github

1.该框架用到的第三方框架

androidTestCompile 'org.mockito:mockito-core:2.5.6'
androidTestCompile 'com.linkedin.dexmaker:dexmaker-mockito:2.2.0'

mockito

单元测试框架

dexmaker

运行在Android Dalvik VM上,利用Java编写,来动态生成DEX字节码的API。为我们在Android上实现AOP编程提供了很好的选择

2.sdk包结构

countly-sdk-android_第1张图片
sdk包结构图.png

openudid包
用于获取设备唯一标识的一种方案

count包
AdvertisingIdAdapter.java
获取谷歌的广告id

CertificateTrustManager.java
https证书信任管理器

ConnectionProcessor.java
将收集到的数据发送给服务器的一个后台任务。
接到发送通知后,将存储在本地的数据一条一条的送给服务端,每送一条,就删除本地对应的那条数据,直到数据为空,此时任务结束,等待下次发送数据的通知。

ConnectionQueue.java
将收集的各个类型的数据,存储在本地,并通知ConnectionProcessor将数据发送到服务端
ConnectionQueue中的记录事件的方法

void recordEvents(final String events) {
    checkInternalState();
    final String data = "app_key=" + appKey_
                      + "×tamp=" + Countly.currentTimestampMs()
                      + "&hour=" + Countly.currentHour()
                      + "&dow=" + Countly.currentDayOfWeek()
                      + "&events=" + events
                      + "&sdk_version=" + Countly.COUNTLY_SDK_VERSION_STRING
                      + "&sdk_name=" + Countly.COUNTLY_SDK_NAME;

    store_.addConnection(data);

    tick();
}

Countly.java
核心类,代码行数比较多,放在后面详细介绍

CountlyStarRating.java
展示一个带星级评分的对话框

CountlyStore.java
本地存储类(sp)
存储各种收集到的数据

CrashDetails.java
收集设备的详细信息,并将这些信息和崩溃信息整合在一起,当APP崩溃时,整合的全部信息都会被上传到服务器

DeviceId.java
设置设备唯一标识,有三种选择:用户自定义,OPEN_UDID和ADVERTISING_ID

DeviceInfo.java
获取设备以及App相关信息

Event.java
定义了待传递事件的数据结构,即上传哪些字段

public String key;
public Map segmentation;
public int count;
public double sum;
public double dur;
public long timestamp;
public int hour;
public int dow;

EventQueue.java
收集数据到本地SP以及从本地获取事件列表

MessagingAdapter.java
通过反射调用CountlyMessaging类的方法,该类在sdk-messaging模块中

OpenUDIDAdapter.java
通过反射调用OpenUDID_manager类的方法

ReferrerReceiver.java
接收com.android.vending.INSTALL_REFERRER的广播

UserData
定义了用户相关的信息,如姓名等等

3. 事件记录分类

3.1 点击事件收集
Countly.sharedInstance().recordEvent("Custom event 1")
3.2 跟踪视图(Activity)
 Countly.sharedInstance().setViewTracking(true);//开启视图跟踪
 Countly.sharedInstance().onStart(this); //在onStart中调用该方法
3.3 崩溃日志收集
 Countly.sharedInstance().enableCrashReporting();

4. 核心类Countly分析

构造方法
利用线程池开启了一个定时任务,每隔60S刷新会话,只要Event队列有数据,就将Event队列中的数据加入到Connection队列中,然后通知后台任务从前到后上传队列中的数据

onCreate方法

Intent intent = activity.getIntent();
Uri data = intent.getData();

主要是获取当前Activity的属性

init方法
需要三个必传参数
context 上下文
serverURL 服务器地址,会校验合法性,并去掉最后一个'/'
appKey App秘钥,只校验的是否为空

关于设备id
默认设置id为null 设备id类型为uuid 且设备支持uuid

在初始方法中,做了以下工作
校验参数合法性
初始化ConnectionQueue参数
创建EventQueue

halt方法
将所有的参数设置为空,并清空Event队列和Connection队列

onStart和onStop方法
这个两个方法需要成对使用,一次onStart和onStop,其实就是一个Activity停留的那一段时间,在每一次的onStart方法中都会记录当前的Activity,同时也会通过beginSession和endSession,记录APP从打开到关闭的持续时间

recordEvent方法

void sendEventsIfNeeded() {
    if (eventQueue_.size() >= EVENT_QUEUE_SIZE_THRESHOLD) {
        connectionQueue_.recordEvents(eventQueue_.events());
    }
}

private static int EVENT_QUEUE_SIZE_THRESHOLD = 10;
调用该方法,会将Event数据存入Event队列,当存入的数据大于等于10条时,将Event队列的数据转化成JsonArry格式移动到Connection队列
移动的同时,Event队列的数据删除(eventQueue_.events()方法会执行这个操作)
通知后台任务将队列中的数据从前到后一条一条上送给服务端,直到队列没有数据为止

recordView方法
在开启视图追踪时,记录的View就是Activity(自动记录),也可以主动记录要记录的View的名字,在记录View相关数据的同时,也会记录两次调用recordView的时间间隔。最终调用recordEvent方法将数据插入Event队列。

setUserData方法
将用户相关的信息,直接放入Connection队列,并清空用户信息

startEvent和endEvent(事件的唯一性由key值决定)
这两个方法应该成对使用,当调用startEvent时,会将此事件暂时记录,当调用endEvent,会将发生在start到event之间的数据,通过调用recordEvent方法加入到Event队列

5. 总结

该框架收集信息的总体流程
数据收集->放入Event队列->放入Connection队列->传递给服务器

其中数据从Event队列转移到Connection队列的触发要求:

  1. Event队列超出设置的最大事件数
  2. 计时器触发(每隔60S一次)
    二者只要满足其一就会触发

Event队列一次添加一个事件
Connection队列一次添加一个Event队列

一旦数据添加到Connection队列,就会自动触发后台任务将数据传递给服务器

传递给服务器的数据是从Conection队列的首部开始一个一个传递给服务器的

每一个Event事件都包含的属性

countlyStore_.addEvent(key, segmentation, timestamp, hour, dow, count, sum, dur);

每一个Connection事件包含的属性

final String data = "app_key=" + appKey_
                      + "×tamp=" + Countly.currentTimestampMs()
                      + "&hour=" + Countly.currentHour()
                      + "&dow=" + Countly.currentDayOfWeek()
                      + "&events=" + events
                      + "&sdk_version=" + Countly.COUNTLY_SDK_VERSION_STRING
                      + "&sdk_name=" + Countly.COUNTLY_SDK_NAME;

        store_.addConnection(data);

你可能感兴趣的:(countly-sdk-android)