iOS 开发每天分享优质文章

iOS生命周期事件之项目应用及个人体会

2018-03-26  本文已影响75人  woniu
心有猛虎,细嗅蔷薇!很多细节性的东西往往对我们SDK采集数据有很大的影响的,特别是在大数据量的采集场景里,一点细节性的差异往往就是蝴蝶效应的再现。所以,搞清楚知识点的定义以及使用场景,对于以后的数据问题能够防患于未然。下面,就我们网脉SDK在项目使用过程中的启动次数的问题为引子,详细分析下APP生命周期事件的监控的差异性。
APP生命事件.png

一、APP生命事件方法的详细介绍:

1、回调方法:application:didFinishLaunchingWithOptions:

      本地通知:UIApplicationDidFinishLaunchingNotification
      触发时机:程序启动并进行初始化的时候后。
      适宜操作:这个阶段应该进行根视图的创建。

2、回调方法:applicationDidBecomeActive:

      本地通知:UIApplicationDidBecomeActiveNotification
      触发时机:程序进入前台并处于活动状态时调用。
      适宜操作:这个阶段应该恢复UI状态(例如游戏状态)。

3、回调方法:applicationWillResignActive:

      本地通知:UIApplicationWillResignActiveNotification
      触发时机:从活动状态进入非活动状态。
      适宜操作:这个阶段应该保存UI状态(例如游戏状态)。

4、回调方法:applicationDidEnterBackground:

      本地通知:UIApplicationDidEnterBackgroundNotification
      触发时机:程序进入后台时调用。
      适宜操作:这个阶段应该保存用户数据,释放一些资源(例如释放数据库资源)。

5、回调方法:applicationWillEnterForeground:

      本地通知:UIApplicationWillEnterForegroundNotification
      触发时机:程序进入前台,但是还没有处于活动状态时调用。
      适宜操作:这个阶段应该恢复用户数据。

6、回调方法:applicationWillTerminate:

      本地通知:UIApplicationWillTerminateNotification
      触发时机:程序被杀死时调用。
      适宜操作:这个阶段应该进行释放一些资源和保存用户数据。(例如数据库的存储)

二、网脉SDK的实际应用

1、网脉SDK对生命事件的统计要求纪元

我们SDK要求统计应用的启动(start)、挂起(suspend)、后台进入前台(resume)三种系统事件,为了区分这三种事件,SDK设置的与之对应的本地通知分别为:UIApplicationDidFinishLaunchingNotification(start)、UIApplicationDidEnterBackgroundNotification(suspend)和UIApplicationWillEnterForegroundNotification(resume),SDK内部监控代码如下:

    //启动通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(APPLaunchingNotification)
                                                 name:UIApplicationDidFinishLaunchingNotification object:nil];
    
    //应用进入前台通知  在启动的时候是不会调动这个通知的,它不是从后台进入到前台的
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ForegroundNotification) 

                                                 name:UIApplicationWillEnterForegroundNotification object:nil];
    
    //进入后台
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(EnterBackgroundNotification)
                                                 name:UIApplicationDidEnterBackgroundNotification object:nil];

2、定义的启动纪元

行业内部(友盟)重新定义了启动事件为:
a:iOS启动定义 = APP启动 + 后台进入前台
b:Android启动定义 = APP启动 + 进入后台30过后再次进入前台
APP使用时长定义 = APP非活跃时间 - APP进入活跃时间
友盟单次启动市场统计原理:http://bbs.umeng.com/thread-6302-1-1.html

Android平台:

在每个Activity的开始和结束时分别调用onResume和onPause方法.
当一个onResume方法与上一个Activity的onPause方法相差30秒,标志新session的开始;当一个onPause方法发生后30秒内没有再触发任何一个Activity的onResume方法,标志该session结束。
如果应用Crash, Android平台处理成onPause, 照例通过30秒规则来判断是否是session的终止.

即Android平台一次完整的启动包括如下三种情况:
1.从启动应用到关闭应用
2.从启动应用到应用退至后台,且在后台运行时间超过30s
3.启动应用后设备黑屏,黑屏时间超过30s
符合以上三种情况的前提下,Android启动次数+1.


iOS平台:

通过监听“UIApplicationDidBecomeActiveNotification(进入活跃状态)”消息来确定session开始;监听“UIApplicationWillResignActiveNotification(进入非活跃状态)”来判定session结束
如果应用crash,iOS平台通过监听“UIApplicationWillTerminateNotification”消息来获取appcrash信息, 当app crash时,相当于结束该session

即iOS平台一次完整的启动包括:
1.从启动应用到关闭应用
2.从启动应用到应用退至后台,此种情况iOS与Android不同,iOS只要退至后台就算本次启动的结束
复合以上两种情况的前提下,iOS启动次数+1.

由于同时使用友盟作为统计工具,所以我们采用和友盟相同的定义来采集系统事件,唯一不同的是友盟使用“UIApplicationDidBecomeActiveNotification”消息来确定session开始;监听“UIApplicationWillResignActiveNotification”来判定session结束。同时,友盟也是使用它们来判断APP的启动和结束(后来才确定,真迟钝)。而网脉SDK获取启动次数为"UIApplicationDidFinishLaunchingNotification(start) "+"UIApplicationWillEnterForegroundNotification (resume)",乍一看"活跃 = 启动 + 后台进入前台"没毛病。然而,事情并没有这么简单,当我们SDK嵌码到浙江新闻、浙江24小时这样的累计百万用户量的APP的时候,问题就来了。

3、问题纪元

部分差异展示.png

通过SDK和友盟采集启动事件的对比,我们发现SDK的启动次数总是少于友盟15%~20%左右,开始的时候是找我们是否有漏发数据的问题,但是查来查去并没有漏发,于是开始从源头上查找问题。
我们猜测"UIApplicationDidBecomeActiveNotification"为友盟采集启动的方法,而非采用我们SDK定义的方法,然后我们开始验证"UIApplicationDidBecomeActiveNotification"的使用场景,通过测试发现,在双击home键,进入APP列表页面的时候,此时APP是处于非活跃状态“UIApplicationWillResignActiveNotification”,SDK认为会话结束(注意:此时并非后台状态)。当再次点击此APP进入前台活跃状态时,会调用“UIApplicationDidBecomeActiveNotification”监听方法,此时启动次数+1。而我们的SDK就是缺少此种情况下启动次数统计。


双击Home-APP列表状态.png

4、验证纪元

问题找到了,我们修改下采集启动次数的监听方法来验证问题是否解决:

 //进入活跃状态  启动、后台进入前台、从双击home键进入APP列表页返回页面
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(BecomeActiveNotification)
                                                 name:UIApplicationDidBecomeActiveNotification object:nil];

在内部SDK验证结果如下:


效果对比.png

通过对比图,我们发现2.0版本采集的数据与友盟相比几乎无差别,而还是用原先方法的1.5.7版本启动次数依然是相差20%左右,问题圆满解决!

5、个人体会总结

事前极为细致的调查不同平台对某些数据的定义,并给出测试报告是十分重要的(难处,总是后知后觉),特别对于大数据分析的公司,因为可能是定义的不同导致的差异,但客户并不一定认可,他们觉得都是启动为什么你的少了那么多呢?是不是你的SDK或者后台分析有什么缺陷呢?而要解释这些问题,都要给客户详细说明并给出确切的证据,他们才会相信,而这又是对双方耐心的考验。
所以,沟通也是十分重要的一环,不可小觑!良好的沟通能力也是一个十分重要的技能,它能避免很多不必要的问题,请诸君共勉。

上一篇下一篇

猜你喜欢

热点阅读