Android产品研发(八)-->App数据统计

来源:互联网 发布:客户档案软件 编辑:程序博客网 时间:2024/06/04 08:13

转载请标明出处:一片枫叶的专栏

上一篇文章中我们介绍了Android社区中比较火的热修复功能,并介绍了目前的几个比较流行的热修复框架,以及各自的优缺点,同时也介绍了一下自身项目中对热修复功能的实践。目前主流的热修复原理上其实分为两种,一种是通过利用dex的加载顺序实现热修复功能,一种是通过native层实现指针替换实现热修复功能,两种各有利弊可以根据自身产品的需要选择不同的方案,具体可参考: Android产品研发(七)–>Apk热修复。

而文本将要介绍一下Android产品中另一项基础功能-数据统计。App数据统计的意义在于通过统计用户的行为方式有针对性的更新展示算法,根据用户的行为习惯更新产品功能等等,具体而言当我们开发好App后就会把它发到应用市场上,但是目前有很多的应用市场(如,豌豆荚,应用宝,安卓市场等),那么问题来了,假如我们想统计我们开发的应用的下载次数,就必须使用统计吧,而且它不仅可以统计我们的应用的下载量,启动次数,还可以统计页面访问量、查看程序的bug等等,所以相对于项目而言产品由于存在着持续的迭代与用户体验,所以做好数据统计工作是一项必不可少的工作。

本文中数据统计主要介绍两种:第三方统计服务和自己实现数据统计功能。

相对而言这两种方式各有利弊,第三方统计服务简单、方便、统计范围广,但是数据保存在第三方,对于一些数据比较敏感的App可能不太喜欢这种方式,而自己实现数据统计功能主要优点就是安全可定制化,当然了缺点也是显而易见的,就是繁琐,复杂。

下面我分别就这两种数据统计方式做一下简单的介绍。

  • 第三方统计服务

一般情况下App中都是使用第三方数据统计服务的,友盟、百度统计等等,这里简单介绍一下友盟统计,其余的都是大同小异。

友盟统计官网
友盟统计中不但有统计相关功能,还提供了错误分析,社会化分享,推送,即时通讯等等,当然这里我们重点分析的是其数据统计功能。

在友盟官网中我们可以看到其对统计服务的介绍,这里我们大概的看一下:
这里写图片描述
可以发现我们提供了用户统计,渠道统计,页面访问路径统计,点击事件统计等等。
那么我们如何才能继承友盟的统计功能的,其在SDK文档介绍中已经做了详细介绍,大概的集成流程是下载友盟SDK jar包,然后引用,并在相应的Activity/Fragment的生命周期方法中调用相关的API。

  • 自己实现数据统计功能

对于一些数据敏感的App来说可能自己实现部分数据统计功能是一个比较不错的选择,当初笔者也做过类似的功能,其原理就是参考友盟的数据统计在App打开的时候执行数据上报功能。

这里简单介绍一下自己实现的数据统计功能的流程:
(1)数据统计上报主要分为两中方式,网络请求上报和文件信息上报;
(2)网络请求上报就是直接调用网络请求若请求失败,则将上报信息保存至本地文件中;
(3)本地上报文件设置阙值和间隔时间,若距离上次上报时间大于阙值或者是文件大小大于阙值则执行上报操作,若上报成功则删除本地数据文件;
(4)本地数据文件在上报之前有加密和压缩操作;
(5)在App打开的时候执行一次数据上报操作,在特定的操作下可以执行上报操作;
(6)上报操作是在Service服务中执行,避免上报操作被由于进程被杀死而中断;

最后贴上为了实现数据上报而自定义的数据统计服务:

/** * Created by aaron on 2016/4/8. * desc:UU打点service */public class UUPointService extends Service {    @Override    public void onCreate() {        super.onCreate();    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        /**         * desc:该service为APP打点service         * 主要实现两个后台服务:         * (1)内存数据上报;         * (2)文件数据上报;         */        if (intent != null && intent.getStringExtra(UUPoint.LOADTYPE) != null && intent.getStringExtra(UUPoint.LOADTYPE).trim().equals(UUPoint.LOADDATA)) {            if (UUPoint.writeMap.size() > 0) {                //(1)转换数据                final List<String> strList = new ArrayList<String>();                Iterator<Map.Entry<String, Integer>> iterator = UUPoint.writeMap.entrySet().iterator();                while (iterator.hasNext()) {                    StringBuffer sb = new StringBuffer();                    Map.Entry<String, Integer> entry = iterator.next();                    String key = entry.getKey();                    Integer count = entry.getValue();                    sb.append(key).append(",").append(count);                    strList.add(sb.toString());                }                if (strList.size() > 0) {                    // 上传服务器数据上传服务器数据                    SystemCommon.ReportLogBatch.Builder builder = SystemCommon.ReportLogBatch.newBuilder();                    builder.addAllLogLine(strList);                    SystemInterface.ReportLogInfoRequest.Builder request = SystemInterface.ReportLogInfoRequest.newBuilder();                    request.setLogData(ByteString.copyFrom(GZipUtils.compress(builder.build().toByteArray())));// 压缩数据包                    NetworkTask task = new NetworkTask(CmdCodeDef.CmdCode.ReportLogInfo_VALUE);                    task.setBusiData(request.build().toByteArray());                    NetworkUtils.executeNetwork(task, new HttpResponse.NetWorkResponse<UUResponseData>() {                        @Override                        public void onSuccessResponse(UUResponseData responseData) {                            if (responseData.getRet() == 0) {                                try {                                    SystemInterface.ReportLogInfoResponse response = SystemInterface.ReportLogInfoResponse.parseFrom(responseData.getBusiData());                                    if (response.getRet() == 0) {                                        /*MLog.i("tab", "########################");                                        for (String str : strList) {                                            MLog.i("tab", str);                                        }*/                                        UUPoint.writeMap.clear();                                        UUPointUtils.setLastPointTime(UUPointService.this);                                        /*MLog.i("tab", "上报数据完成################");*/                                    } else {                                        UUPoint.saveWriteToIO(UUPointService.this);// 将写map中的数据持久化到IO                                    }                                } catch (Exception e) {                                    UUPoint.saveWriteToIO(UUPointService.this);// 将写map中的数据持久化到IO                                }                            } else {                                UUPoint.saveWriteToIO(UUPointService.this);// 将写map中的数据持久化到IO                            }                        }                        @Override                        public void onError(VolleyError errorResponse) {                            MLog.i("tab", "保存到本地文件");                            UUPoint.saveWriteToIO(UUPointService.this);                        }                        @Override                        public void networkFinish() {                        }                    });                }            }        }        // 上传文件        else if (intent != null && intent.getStringExtra(UUPoint.LOADTYPE) != null && intent.getStringExtra(UUPoint.LOADTYPE).trim().equals(UUPoint.LOADFILE)) {            File file = new File(Config.CountFile);            List<File> fileList = Arrays.asList(file.listFiles());            if (fileList != null && fileList.size() > 0) {                //按文件名称排序                Collections.sort(fileList, new Comparator<File>() {                    @Override                    public int compare(File lhs, File rhs) {                        return rhs.getName().compareTo(lhs.getName());                    }                });                // 上传文件                for (final File files : fileList) {                    // 先解密,在使用票据加密                    FileEncrypter.decrypt(files, UUPoint.secretKey);// 解密                    if (Config.isNetworkConnected(UUPointService.this)) {                        NetworkTask networkTask = new NetworkTask(CmdCodeDef.CmdCode.ReportLogFile_VALUE);                        networkTask.setUploadDataFile(true);// 上传大点数据文件                        networkTask.setBusiData(UUPointUtils.getBytesFromFile(files));                        NetworkUtils.executeNetwork(networkTask, new HttpResponse.NetWorkResponse<UUResponseData>() {                            @Override                            public void onSuccessResponse(UUResponseData responseData) {                                if (responseData.getRet() == 0) {                                    try {                                        SystemInterface.ReportLogInfoResponse response = SystemInterface.ReportLogInfoResponse.parseFrom(responseData.getBusiData());                                        if (response.getRet() == 0) {                                            // 上传成功, 删除加密文件                                            files.delete();                                            MLog.i("tab", "上传文件完成" + files.getName() + "######################");                                        } else {                                            FileEncrypter.encrypt(files, UUPoint.secretKey);// 上传失败, 重新加密文件                                        }                                    } catch (Exception e) {                                        e.printStackTrace();                                        FileEncrypter.encrypt(files, UUPoint.secretKey);// 上传失败, 重新加密文件                                    }                                } else {                                    FileEncrypter.encrypt(files, UUPoint.secretKey);// 上传失败, 重新加密文件                                }                            }                            @Override                            public void onError(VolleyError errorResponse) {                                MLog.i("tab", errorResponse.toString());                                FileEncrypter.encrypt(files, UUPoint.secretKey);// 上传失败, 重新加密文件                            }                            @Override                            public void networkFinish() {                            }                        });                    }                }            }        }        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        super.onDestroy();    }    @Override    public IBinder onBind(Intent intent) {        return null;    }}

总结:
一般而言直接使用第三方统计服务就已经可以满足绝大部分的业务需求了,当然了如果数据比较敏感也可以自己实现数据上报统计的功能。

另外对产品研发技术,技巧,实践方面感兴趣的同学可以参考我的:
Android产品研发–>总结(持续更新)
Android产品研发(一)–>实用开发规范
Android产品研发(二)–>启动页优化
Android产品研发(三)–>基类Activity
Android产品研发(四)–>减小Apk大小
Android产品研发(五)–>多渠道打包
Android产品研发(六)–>Apk混淆
Android产品研发(七)–>Apk热修复


本文以同步至github中:https://github.com/yipianfengye/AndroidProject,欢迎star和follow


4 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 脸打架打肿了怎么办 人家不加我qq好友怎么办 一个好友被删了怎么办 dnf脸黑怎么办还有办法 我想登别人微信怎么办 昌硕工资没到怎么办 昌硕离职不批怎么办 昌硕工资不到卡怎么办 上海人去苏州工作社保怎么办 娶个个脾气暴躁的媳妇怎么办 满脸的黑头痘痘怎么办 脚底磨起泡不敢走路怎么办 老婆老是找异性朋友怎么办 喜欢的人有对象怎么办 遇到了更喜欢的怎么办 8岁骨龄11岁怎么办啊 13岁初中生有思想不听话怎么办 交朋友找对象喜欢颜值高的怎么办 儿子找对象不听父母怎么办 缺爱怎么办的搞笑回答 对象说有人追她怎么办 说了一句话媳妇非常生气怎么办 柔顺后头发太臭怎么办 积分兑换手机被骗了怎么办 老板对你的上级不满怎么办 如果老板不给工资怎么办 手机号码被标记为其他公司怎么办? 被标记为骚扰电话怎么办 手机被标记骚扰电话怎么办 360摄像头不支持5g怎么办 摄像头不支持5g网络怎么办 家里的wifi卡了怎么办 办信用卡没有座机号码怎么办 拨打电话时显示号码有误怎么办 个体营业执照怎么办企业支付宝 没满16岁怎么办电话卡 我的电话卡丢了怎么办 公司注销地税没有补齐怎么办 公司没有固定电话怎么办信用卡 申请信用卡公司没有固定电话怎么办 办理信用卡公司没有固定电话怎么办