iOS Voip套接字不会在后台运行

我得到一个VOIP套接字在iOS应用程序的后台运行。

我的连接工作正常,但当我的应用程序进入后台时,它不会醒来。 如果我打开应用程序,它会响应它在睡觉时收到的任何消息。

我build立了这样的stream:

CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (CFStringRef) @"test.iusealocaltestserver.com", 5060, &myReadStream, &myWriteStream); CFReadStreamSetProperty ( myReadStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP ); CFSocketNativeHandle native; CFDataRef nativeProp = CFReadStreamCopyProperty(myReadStream, kCFStreamPropertySocketNativeHandle); CFDataGetBytes(nativeProp, CFRangeMake(0, CFDataGetLength(nativeProp)), (UInt8 *)&native); CFRelease(nativeProp); CFSocketRef theSocket = CFSocketCreateWithNative(kCFAllocatorDefault, native, 0, NULL, NULL); CFSocketGetContext(theSocket,&theContext); CFOptionFlags readStreamEvents = kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered | kCFStreamEventOpenCompleted; CFReadStreamSetClient(myReadStream, readStreamEvents, (CFReadStreamClientCallBack)&MyCFReadStreamCallback, (CFStreamClientContext *)(&theContext)); CFReadStreamScheduleWithRunLoop(myReadStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); 

那么我的callback是这样设置的:

 static void MyCFReadStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void *pInfo); static void MyCFReadStreamCallback (CFReadStreamRef stream, CFStreamEventType type, void *pInfo) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog(@"Callback Happened"); [pool release]; } 

当我收到数据并且应用程序已经打开时,“发生的callback”正在被调用,但是如果应用程序已经最小化,则不会。 然而,当应用程序恢复时,它处理收到的数据,同时最小化。

我添加了voip标签到info.plist。 我的CFReadStreamSetProperty返回true。 我在一个不是模拟器的设备上运行。 它仍然不工作,所以我不知道我的问题可能是什么。 我可能只是做了一些愚蠢的事情,但几乎没有在线检查我的代码。

编辑:我无法testing任何答案,因为我不再在这个项目上工作,并没有访问一个mac / ios sdk。 如果有类似问题的人发现下面的答案有用,请让我知道,我会投票给它最好的答案。

如果你想让你的VOIP应用程序在后台运行,除了在plist文件中的基本设置,你需要一个属性设置为VOIP的TCP套接字,比你的应用程序进入后台的iOS系统会照顾这个套接字,除了tcp socket之外,每件事情都是“睡眠”的。 如果VOIP服务器发送一些数据认为TCP套接字,你的应用程序将被唤醒10秒。 在此期间,您可以发布本地通知。

只有TCP套接字可以设置为VOIP套接字。 但是据我所知,大多数VOIP应用都是基于UDP套接字的。 如果您不想将控制套接字与数据套接字分开。 你应该创build另一个专注于唤醒你的应用程序的tcp套接字,并且从我个人的经验来看,保持这个“清醒”信号和真正的sip控制信号是非常难以同步的,应用程序总是会错过sip邀请请求。

所以,最好的办法是将sip控制单从UDP数据套接字中分离出来,使之成为一个tcp套接字,这是最好的解决scheme,但从不使用tcp套接字来传输语音数据。

另一个肮脏的方法:保持应用程序始终保持清醒。 正如我所说的,每个收到的应用程序单独的TCP认为'VOIP'tcp套接字将保持应用程序唤醒10秒,所以在这个持续时间结束后(9秒之后),你可以发送一个响应给服务器请求另一个信号,当下一个信号到达时,应用程序将再次唤醒,9秒后再次发送响应。 继续这样做,你的应用程序将永远清醒。

我被困在完全相同的情况下。
我的问题是,我已经configuration了多个套接字作为一个VoIP套接字

你可以在苹果的voip文档中看到他们说:
“为VoIP使用configuration一个应用程序套接字”

我想他们只是根据一个sockets唤醒你的应用程序。

所有其他提到的东西仍然是正确的:

  • kCFStreamNetworkServiceTypeVoIP
  • 'info.plist'UIBackgroundModes:voip,audio
  • 'info.plist'UIRequiresPersistentWifi密钥
  • 将不会在模拟器上工作

我也面临同样的问题。 但在我的情况下,一切工作正常,除非networking发生变化。 我使用苹果“可达性”类来检测networking变化。 如果应用程序在后台直到某个时候我的套接字正在工作,即使我手动切换我的networking以下。

  1. wifi – > 3G
  2. 3G – >无线

过了一段时间,让我们再说一遍手动尝试networking切换。 没有什么是幸福,似乎我的应用程序没有检测到networking的变化。 我读了下面的苹果文档。 我确定做错了(或)破坏了步骤3和6。

实施VoIP应用有几个要求:

1.将UIBackgroundModes键添加到应用程序的Info.plist文件中。 将此密钥的值设置为包含voipstring的数组。

  1. 为VoIP使用configuration一个应用套接字。

  2. 在移到后台之前,调用setKeepAliveTimeout:handler:方法来安装一个定期执行的处理程序。 您的应用程序可以使用此处理程序来维护其服务连接。

  3. configuration您的audio会话以处理转入和转出活动使用。

5.为确保在iPhone上获得更好的用户体验,请使用核心电话框架来调整与基于蜂窝电话呼叫相关的行为; 请参阅核心电话框架参考。

  1. 为了确保您的VoIP应用程序具有良好的性能,请使用系统configuration框架来检测networking更改,并尽可能让您的应用程序进入睡眠状态。

您可能需要在Info.plist中设置<key>UIBackgroundModes</key><array><string>audio</string></array> ,并且您需要确保audio会话处于活动状态你切换应用程序(假设你不会突然开始录制/播放音乐/无论你的应用程序在后台)。

文档说,“audio”可以让你在后台播放audio,但是这大概也适用于录制audio。 如果不起作用,您可以尝试几件事情:

  • 同时设置“voip”和“audio”。
  • 玩沉默(这可能是最简单的与audio队列API)。

你的应用程序委托中有“applicationDidEnterBackground:”吗? 我非常肯定,我已经阅读了某处(我找不到),您需要定义为ios识别您支持背景模式。 你不需要实现任何东西。

例如

 - (void)applicationDidEnterBackground:(UIApplication *)application { }