一般来说, IOS很少给App后台运行的权限. 仅有的方式就是 VoIP. IOS少有的为VoIP应用提供了后台socket连接,定期唤醒并且随开机启动的权限.而这些就是IOS上实现VoIP App的关键. 苹果官方文档对于的描述就短短的一页(点击这里),很多细节没有提及. 这篇微博通过具体实现和查阅资料,补充了这些细节.并且列举出了在实现过程中可能遇到的问题, 作为参考.
PS:此节纯用来占座.如果你你E文不好或者想直接切入正题, 请看下一标题.
There are several requirements for implementing a VoIP app:
- Add the UIBackgroundModes key to your app’s Info.plist file. Set the value of this key to an array that includes the voip string.
- Configure one of the app’s sockets for VoIP usage.
- Before moving to the background, call the setKeepAliveTimeout:handler: method to install a handler to be executed periodically. Your app can use this handler to maintain its service connection.
- Configure your audio session to handle transitions to and from active use.
- To ensure a better user experience on iPhone, use the Core Telephony framework to adjust your behavior in relation to cell-based phone calls; see Core Telephony Framework Reference.
- To ensure good performance for your VoIP app, use the System Configuration framework to detect network changes and allow your app to sleep as much as possible.
关于IOS为VoIP应用提供的特殊权限和实现方法,我的描述如下:
socket
需要在应用第一次启动的时候创建, 并标记为"此socket
用于VoIP服务". 这样当App切换到后台的时候,IOS会接管这个标记为"用于VoIP服务"的socket
. 这个socket
的响应函数(比如,一个delegate
,或者是个block
)会正常的响应, 就像App还在前台一样.socket
有任何数据从服务端传来, 你在app里为socket
写的响应函数都会做处理.但是, 你只有最多10s的时间来干你想干的事情. 也就意味着你在响应函数里新建一个大于10s的timer
是没有意义的. 并且IOS并不保证给你足够10s的时间,视系统情况而定.socket
的响应函数里, 你能通过NSLocalNotification
来通知用户"电话来了". 除此之外, 你没法做其他任何视觉上的动作来提醒用户, 因为你的app还处于某个不知道的次元, 甚至连window
都还没创建.NSLocalNotification
的样式是banner
还是alert
. 我知道你钟爱后者, 但是决定权在用户手里.t
, 和一个定期执行的handler
, IOS系统会在每次经过t
时间的时候调用一次这个handler
. 但是IOS不保证这个handler
会准时运行, 只保证在时间t
范围内的某个点会执行一次.handler
处理socket的断线重连操作. 因为网络不稳定, 或者用户开启飞行模式等原因, 我们用于voip服务的socket
会断开连接. 在这个handler
里,如果发现连接断开,我们只需要跟条目1一样的创建socket
,设置一样的socket
响应函数,一切又会恢复正常.handler
做太多事情, 因为它也有10s魔咒.(据不完全统计,苹果所有的后台处理都有这个10s限制. 不保证绝对正确哈, 仅供参考)application:didFinishLaunchingWithOptions:
会被调用. 但是,请时刻提醒自己我们的app仍然处于后台. 我们以前总在这里创建window
创建rootController
, 现在不必了. 现在我们需要的就是把可爱的socket
连上, 想在条目1里一样,让一切回归正常(我不去写歌词真浪费了^_^).application:didFinishLaunchingWithOptions:
里你能通过[application applicationState] == UIApplicationStateBackground
来判断是正常启动应用还是系统自动启动, 然后决定该创建window
还是创建voip的socket
.