美文网首页iOS 开发每天分享优质文章
iOS生命周期事件之项目应用及个人体会

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

作者: woniu | 来源:发表于2018-03-26 16:39 被阅读75次
    心有猛虎,细嗅蔷薇!很多细节性的东西往往对我们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或者后台分析有什么缺陷呢?而要解释这些问题,都要给客户详细说明并给出确切的证据,他们才会相信,而这又是对双方耐心的考验。
    所以,沟通也是十分重要的一环,不可小觑!良好的沟通能力也是一个十分重要的技能,它能避免很多不必要的问题,请诸君共勉。

    • 再叨叨几句:
      上面一个心酸历程只有自己能体会,这么个小小的问题只是因为我们对采集系统事件种类的要求,最终导致了启动事件对友盟的20%的差异。失之毫厘,谬之千里!看似小小的问题其实只是冰山一角,发现问题、验证问题、解决问题直到最后客户认可并交付(客户要求最低上万的数据量),中间经历了大量的沟通(内部沟通、客户沟通)、测试(动员全公司以及分公司人员,说出来都是泪)。不过,对自己的技能提升也是一个很大的帮助,希望以后能更加强大些,既能避免采坑,又能很好的填坑!

    相关文章

      网友评论

        本文标题:iOS生命周期事件之项目应用及个人体会

        本文链接:https://www.haomeiwen.com/subject/mtmrcftx.html