zoukankan      html  css  js  c++  java
  • iOS后台运行机制-实践总结

      从2015年,接触到的项目里,就会有这样的需求:APP需要像Android那样,在后台状态下,执行正常的功能。到现在已经一年多了吧,一直在研究这个方面,写下一些心得,希望与大家共同交流探讨。

      首先,我们要知道,苹果对APP占用硬件资源管的很严,更不要说应用后台时候的资源占用了。正常情况下,使用应用时,APP从硬盘加载到内存,开始工作;当用户按下home键,APP便被挂起,依然驻留在内存中,这种状态下,不调用苹果已开放的几种后台方法,程序便不会运行;如果在这个时候,使程序继续运行,则为后台状态;如果当前内存将要不够用时,系统会自动把之前挂起状态下的APP请出内存。所以我们看到,有些时候打开APP时,还是上次退出时的那个页面那些数据,有时则是重新从闪屏进入。

      这样,就知道了后台运行最大的前置条件——APP处于内存中的挂起状态。

      然后,再来看看上面说到的苹果已开放的后台运行方法。先看这张图

      

      很明显,我们项目里能用的机制就这么多,Background Audio,这是后台的音频,这个很早之前便有,可以实现后台的声音播放。去年的项目里用它在后台一直播放没有声音的文件,结果审核失败。

      在这里说一下去年做的那个项目的需求,用户类型A可以在任何时刻查看用户类型B的地理位置。这个功能有点像iPhone上的『查找朋友』,不知道的朋友请自行了解(想知道你的朋友在哪里吗,想知道你的另一半在哪里吗,对了,就用它);A想看B的时候,B需要上传自己的当前位置给服务器;先不考虑APP在挂起状态怎么做,先说APP在活动状态下,服务器想和客户端进行通信,告诉客户端要上传自己的位置了,这种服务器主动通信,常用到的就是socket和推送通知。我决定用推送,在APP收到来自APNS的推送时,就进行定位并上传。

      然而,按下home键进入挂起状态时,程序是不会执行的,所以也获取不到B的位置。BOSS大为恼火,Android分分钟干完的事,你怎么就搞不定呢(脑补:再搞不出来就滚蛋)。

      当时第一次接触苹果这些后台机制,探索之路弯弯曲曲,就不一一表述了。最后用静默推送解决了这个问题:Remote Notification!原理非常简单,不过苹果的初衷不是让我这样用的……,说一下这个机制的应用场景:以往聊天类应用接受推送后点进去需要再收一次信息,这情况在QQ、微信等应用上最为明显。不过拥有了这个接口后,这情况将不复存在,以后推送将能够直接启动后台任务,在后台就已经接收到信息,点开APP不需要去拉取。

      so,在A查看B位置的时候,给B一条静默推送,B在后台定位并上传信息。这个唤起时间比较短,在3-5秒左右,有时候B网络不好,没有上传成功就又被挂起了,就需要重复进行。这个机制添加方法和推送一样,只有一点区别,就是委托方法不同。普通推送会执行这个回调:

    1 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    2 
    3     DDLogDebug(@"[普通推送]%@", userInfo);
    4 }

      而勾选住上面那个推送唤醒,就会回调这个方法:

    1 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    2     DDLogDebug(@"[后台推送]%@", userInfo);
    3     completionHandler(UIBackgroundFetchResultNewData);
    4 }

      可以在这个回调里,调用定位请求之类的。

      本以为解决了问题,BOSS试了,也觉得可以。就喜滋滋的等着升职加薪走上人生巅峰,咳咳,又做梦了。

      "咋么回事呃,现在又定不到位了,赶紧搞好"还没到两个小时,BOSS气呼呼的跑过来喷了一顿。说完之后的0.01秒,我就知道是怎么回事了,"听我解释啊,老板"还没说出口,他就摔门而出,留下欲哭无泪的我。只有两个原因,一、APP被人为上划kill掉;二、APP被系统回收了,kill 了。

      就酱,明知山有虎,偏向虎山行。为了不让系统回收APP,我非常强硬的,加上了Background Audio。结果可想而知,被拒绝的同时,收到一封英文邮件,问我为什么这样做,如有异议,可提出。哎,总算松了一口气,可以离职了(个人原因)。

      换了公司,需求也不一样了,APP需要每五秒和服务器进行一次数据交换;以下,用到的是VoIP。

      刚开始的时候,推送唤醒机制还可以,不过林子大了什么鸟都有,一样的型号一样的设置,有台iPhone就是唤醒不了,只能尝试新方法。想起QQ语音时,切到后台依然可以通话,我想,就是它了。VoIP:后台语音服务,类似Skype通话应用需要调用,可进行后台的语音通话。既然是语音通话,那么肯定是常连接,于是,有了以下代码。

     1 @implementation NSStream(StreamsToHost)
     2 
     3 + (void)getStreamsToHostNamed:(NSString *)hostName
     4                          port:(UInt32)port
     5                   inputStream:(out __strong NSInputStream **)inputStreamPtr
     6                  outputStream:(out __strong NSOutputStream **)outputStreamPtr
     7 {
     8     CFReadStreamRef     readStream;
     9     CFWriteStreamRef    writeStream;
    10     
    11     assert(hostName != nil);
    12     assert( (port > 0) && (port < 65536) );
    13     assert( (inputStreamPtr != NULL) || (outputStreamPtr != NULL) );
    14     
    15     readStream = NULL;
    16     writeStream = NULL;
    17     
    18     CFStreamCreatePairWithSocketToHost(
    19                                        NULL,
    20                                        (__bridge CFStringRef) hostName,
    21                                        port,
    22                                        ((inputStreamPtr  != NULL) ? &readStream : NULL),
    23                                        ((outputStreamPtr != NULL) ? &writeStream : NULL)
    24                                        );
    25     
    26     if (inputStreamPtr != NULL) {
    27         *inputStreamPtr  = CFBridgingRelease(readStream);
    28     }
    29     
    30     if (outputStreamPtr != NULL) {
    31         *outputStreamPtr = CFBridgingRelease(writeStream);
    32     }
    33 }
    34 
    35 @end

      给NSStream加了一个类目。然后还需要一个server,我就不写了;发起连接请求让客户端与server保持通信,这些代码也太多了,就不贴了。勾选Voice over IP后,APP挂起状态时,系统会接管socket会话句柄,当收到从server发来的数据流时,就会唤起APP进入后台执行代码。这个唤起时间要长一些,可以在十秒多点。已经测试成功,但是还没有提交审核,还需要给它一个外套,不然就像上次一样被拒绝。

      一直在探索,因为以上方法并不完美,而且项目对后台的要求比较苛刻,事实上,用户在使用APP时,会有很多场景,最常见的就是弱网络,在这个场景下,不管是推送还是socket都无法收到内容,所以像这种需要依赖外力唤起的方式,弊端还是相当明显。

      已经感觉到后面写的比较仓促,VoIP涉及的内容还是比较多,还没有一一吃透,还是心急了些。个人知识有限,如有错误,欢迎指正。

      

  • 相关阅读:
    python自动生成小学四则运算题目
    软件工程第一章心得体会
    Python微信机器人
    利用python进行微信好友分析
    python操作数据库读书笔记
    初学爬虫之访问goole网页与爬取中国大学排名。
    python之预测体育竞技分析
    5、用python写一个自己的网页
    用turtle实现动态汉诺塔
    面向对象与正则表达式的学习(自动更正,和代数运算)
  • 原文地址:https://www.cnblogs.com/ChinaLoong/p/5498821.html
Copyright © 2011-2022 走看看