iOS后台运行机制-实践总结

Posted 木子丶礼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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涉及的内容还是比较多,还没有一一吃透,还是心急了些。个人知识有限,如有错误,欢迎指正。

  

以上是关于iOS后台运行机制-实践总结的主要内容,如果未能解决你的问题,请参考以下文章

第六周周总结

从实践谈iOS生命周期

APP测试中ios和androis的区别,有哪些注意点

ios系统的特点

android应用和ios的区别是啥

线程机制CLR线程池以及应用程序域