Android教师端阿里埋点分析

一. 爱学习教师端需求分析

教师端当前埋点需求,简单描述就是: 基础数据 , “线” , “点” 三部分;

1.基础数据

BI需要记录用户的当前使用环境的基本数据,举个栗子如:设备IMEI , 经纬度, 客户端当前的毫秒值,设备型号,品牌 …

2.线

收集用户的使用行为,把页面的跳转都可以归纳为”线”的部分,目的了解用户使用app的行为线,在行为线的过程中还伴随着浏览资源数据的收集,例如:用户浏览课件视频的ID

3.点

收集特殊行为,例如:分享

二. 教师端当前埋点情况

根据BI提供的页面ID,自定义属性, 在页面抽取的基类中初始化埋点:

1.初始化

/**
 * 通过EndPoint、accessKeyID、accessKeySecret 构建日志服务客户端
 * @endPoint: 服务访问入口,参见 https://help.aliyun.com/document_detail/29008.html
 */
final LOGClient myClient = new LOGClient("cn-beijing.log.aliyuncs.com", "LTAICRtCfbl0u55m",
        "nrRJLautQTQzQopzePrP2NeKlEZAx9", "axx-logs");

/* 创建logGroup */
final LogGroup logGroup = new LogGroup();

2.抽取页面参数model(减少篇幅,简化代码)

public class AliLogBean {

    private String pad = "";
    private String da_src = "";
    private String rpad = "";
    private String pp2 = "";
}

3.定义数据收集,发射公共方法

/**
 * 阿里统计 2017.5
 * @param aliLogBean
 */
public void aliLog(AliLogBean aliLogBean){
   
    logGroup2.PutLog(log);
    //发送log ,在后台发送数据,以防止阻塞主线程
    Thread t = new Thread() {
        public void run() {
            try {
                myClient.PostLog(logGroup2, "user-log");
            } catch (LogException e) {
                e.printStackTrace();
            }
        }
    };
    t.start();

4.页面发送

QQ截图20170601180956

由于只记录跳转的轨迹,而不记录返回的轨迹,根据android中activity的生命周期,这部分是放在onCreate()中进行的

三. 关于埋点阅读的一些文章的总结

这是阿里云栖社区里  https://yq.aliyun.com/articles/8238   关于埋点的一篇文章内容比较概括, 但观点可以借鉴,主要说到:

1.代码埋点数据收集

我们现有的埋点方案应该就是这个;

优点:数据收集准确性高,可以完全契合需求(页面跳转线数据的收集)

缺点: 埋点代码分布到各个页面, 耦合性高, 代码不优雅

2.无埋点数据收集

无埋点暂且理解为一种集中数据收集,android这一块主要就是根据Page + ViewTree 的方式对页面的组件进行定位,viewtree概念图如下:

QQ截图20170601183647

注重于针对view的单点数据收集,并且在遍历vietree的同时非常的消耗性能,来看了两篇关于埋点的文章 <Android AOP之字节码插桩>  http://www.jianshu.com/p/c202853059b4   和 <Android 无埋点数据收集SDK关键技术> http://www.jianshu.com/p/b5ffe845fe2d?from=jiantop.com  ;

Android中AOP框架的局限性:

Dexposed,Xposed的缺陷很明显,xposed需要root权限,Dexposed只对部分系统版本有效。(这两个对于现在的Andorid 来说完全可以放弃)
与之相比AspactJ没有这些缺点,但是aspactJ作为一个AOP的框架来讲对于我们来讲太重了,不仅方法数大增,而且还有一堆AspactJ的依赖要引入项目中(这些代码定义了aspactJ框架诸如切点等概念)。更重要的是我们的目标仅仅是按照一些简单的切点(用户点击等)收集数据,而不是将整个项目开发从OOP过渡到AOP。
AspactJ对于我们想要实现的数据收集需求太重了,但是这种编译期操作class文件字节码实现AOP的方式对我们来说是合适的。

四.个人理解

关于当前Andorid 教师端的埋点,有需要优化的地方,例如:初始化不应在BaseActivity中进行,而应该放在Application中, 还有现在的点完全分布的, 应该对点进行集中整理,方便管理,  至于自动化埋点 和  上述的无埋点数据收集, 主要针对原生的页面, 着重于组件的点击事件收集(个人理解为着重于”点”数据收集),   并且在数据收集的准确性和性能消耗上不占优势,   我们BI业务需求着重于”线”数据收集, 对于教师端的APP 我们为混合开发,大部分的页面交互都是前端插件和原生页面之间的,且原生页面占比甚少, 也是我们业务的一个特殊性! 关于之前考虑到的点数据的变化, 想到走接口, 本地维护映射表的方式以解决, 就这个问题个人和吴世勇交流过, 约定的点数据是不会发生变化的,   也就不存在这个问题了!

个人观点,欢迎指正!

Android Easypermission的介绍

1.相关文档

官方文档: https://github.com/googlesamples/easypermissions

运行时权限官方文档介绍:https://developer.android.com/training/permissions/requesting.html

2.为什么使用Easypermissions

Android M对权限系统进行了改变。Android M之前所需权限只需要AndroidManifest中申请即可。但更新Android M系统后,部分“Dangerous Permission”需要在运行时询问申请。

Android 权限分类:

Nomal Permission:

ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS

Dangerous Permission:

group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE
  permission:android.permission.READ_CALL_LOG
  permission:android.permission.READ_PHONE_STATE
  permission:android.permission.CALL_PHONE
  permission:android.permission.WRITE_CALL_LOG
  permission:android.permission.USE_SIP
  permission:android.permission.PROCESS_OUTGOING_CALLS
  permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
  permission:android.permission.CAMERA

group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS
  permission:android.permission.READ_SMS
  permission:android.permission.RECEIVE_WAP_PUSH
  permission:android.permission.RECEIVE_MMS
  permission:android.permission.RECEIVE_SMS
  permission:android.permission.SEND_SMS
  permission:android.permission.READ_CELL_BROADCASTS

123

运行时权限申请

代码中如果需要申请运行时权限步骤:

1 检查运行时权限

ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED

2 申请权限

ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

3 接收权限处理结果

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

以上即是google建议的运行时权限处理过程。代码量和处理地方还是比较繁琐的。so,Easypermissions应运而生。

3.如何使用

引入库

dependencies {
  compile 'pub.devrel:easypermissions:0.1.9'
}

easypermissions处理权限分为3步:

1 检查权限

String[] perms = {Manifest.permission.CAMERA, Manifest.permission.CHANGE_WIFI_STATE};
if (EasyPermissions.hasPermissions(this, perms)) {
   //...     
} else {
    //...
}

2 申请权限

EasyPermissions.requestPermissions(this, "拍照需要摄像头权限",
                    RC_CAMERA_AND_WIFI, perms);

3 实现EasyPermissions.PermissionCallbacks接口,直接处理权限是否成功申请

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        // Forward results to EasyPermissions
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

    //成功
    @Override
    public void onPermissionsGranted(int requestCode, List<String> list) {
        // Some permissions have been granted
        // ...
    }

    //失败
    @Override
    public void onPermissionsDenied(int requestCode, List<String> list) {
        // Some permissions have been denied
        // ...
    }

4.总结

Easypermissions主要简化了对权限申请结果的处理和判断,直接以接口的方式回调处理结果.不需要再自行进行处理,代码简介明了.