iOS Voip Socket не будет работать в фоновом режиме
Я получаю VOIP-сокет для фонового запуска в приложении для iOS.
Мое соединение работает нормально, но оно не проснется, когда мое приложение перейдет в фоновый режим. Если я снова открою приложение, оно ответит на любые сообщения, полученные во время сна.
Я настроил свой поток так:
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);
Тогда мой обратный вызов настроен так:
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 Happened" вызывается, когда я получаю данные, и приложение открыто, но это не так, если приложение свернуто. Однако, когда приложение возвращается, оно обрабатывает любые данные, полученные при минимизации.
Я добавил тэг voip в список info.plist. Мой CFReadStreamSetProperty возвращает true. Я работаю на устройстве, а не на симуляторе. Это все еще не работает, поэтому я не знаю, в чем может быть моя проблема. Я, наверное, просто сделал что-то глупое, но в интернете почти ничего не проверяется.
РЕДАКТИРОВАТЬ: я не могу проверить ни один из ответов, потому что я больше не работаю над этим проектом и не имею доступа к Mac / IOS SDK. Если кто-то с подобной проблемой нашел один из приведенных ниже ответов полезным, дайте мне знать, и я проголосую за лучший ответ.
5 ответов
Если вы хотите, чтобы ваше приложение VOIP работало в фоновом режиме, за исключением тех базовых настроек в файле plist, вам нужен сокет TCP, свойство которого установлено в VOIP, а система iOS позаботится об этом сокете, когда ваше приложение войдет в фоновый режим, каждая вещь была "спящей", за исключением этого сокета TCP. и если VOIP-сервер отправит некоторые данные, полагая, что TCP-сокет, ваше приложение будет активировано в течение 10 секунд. За это время вы можете опубликовать локальное уведомление.
Только Tcp-сокет может быть установлен как VOIP-сокет. Но насколько я знаю, в основном приложения VOIP основаны на сокете UDP. если вы не хотите отделять управляющий сокет от сокета данных. вам следует создать еще один сокет tcp, который предназначен для "пробуждения" вашего приложения, и из моего личного опыта очень трудно поддерживать синхронизацию этого "пробужденного" сигнала и реального управляющего сигнала SIP, приложение всегда пропускает запрос SIP-приглашения.
Таким образом, лучший способ - отделить одиночный элемент управления sip от сокета данных UDP, сделать его как сокет TCP, это лучшее решение, но никогда не используйте сокет TCP для передачи голосовых данных.
Другой грязный способ: держать приложение бодрствующим все время. Как я уже сказал, каждый TCP-сингл, полученный приложением, думал, что tcp-сокет 'VOIP' будет держать приложение в активном состоянии в течение 10 секунд, поэтому по окончании этого периода (через 9 секунд) вы можете отправить ответ на сервер, чтобы запросить другой сигнал, когда поступит следующий сигнал, приложение снова проснется, через 9 секунд снова отправит ответ. продолжайте делать это, ваше приложение проснется навсегда.
Я застрял с точно таким же сценарием.
Моя проблема заключалась в том, что я настроил более одного сокета в качестве сокета Voip.
Вы можете увидеть в документации Apple о VoIP, что они говорят:
"Настройте один из сокетов приложения для использования VoIP"
Я предполагаю, что они пробуждают ваше приложение только по одному сокету.
все другие упомянутые вещи все еще правильны:
- kCFStreamNetworkServiceTypeVoIP
- 'info.plist' UIBackgroundModes: voip, audio
- 'info.plist' UIRequiresPersistentWifi ключ
- НЕ будет работать над симулятором
Я тоже сталкиваюсь с той же проблемой. но в моем случае все работает нормально, если не происходят изменения в сети. Я использовал яблочный класс "достижимости" для обнаружения изменений в сети. если приложение работает в фоновом режиме до какого-то времени, мой сокет работает, даже если я вручную переключил свою сеть для следующего.
- Wi-Fi -> 3 г
- 3g -> Wi-Fi
Через некоторое время, скажем снова, я пытаюсь переключить сеть вручную. ничто не радует, кажется, мое приложение не обнаруживает сетевых изменений. Я прочитал ниже Apple Doc. я уверен, что неправильно (или) неправильно понял шаги 3 и 6.
Существует несколько требований для реализации приложения VoIP:
1. Добавьте ключ UIBackgroundModes в файл Info.plist вашего приложения. Установите значение этого ключа для массива, который включает строку voip.
Настройте один из сокетов приложения для использования VoIP.
Прежде чем перейти к фону, вызовите метод setKeepAliveTimeout:handler: для установки обработчика, который будет выполняться периодически. Ваше приложение может использовать этот обработчик для поддержания своего сервисного соединения.
Сконфигурируйте ваш аудио сеанс для обработки переходов в активное использование.
5. Чтобы обеспечить лучшее взаимодействие с пользователем на iPhone, используйте платформу Core Telephony для настройки вашего поведения в отношении телефонных звонков на сотовой основе; см. Базовую Ссылку Платформы телефонии.
- Чтобы обеспечить хорошую производительность для вашего VoIP-приложения, используйте инфраструктуру конфигурации системы, чтобы обнаружить изменения в сети и позволить вашему приложению как можно дольше спать.
Вам может понадобиться установить <key>UIBackgroundModes</key><array><string>audio</string></array>
в Info.plist, и вы должны убедиться, что аудио сеанс активен / запущен / что угодно, прежде чем переключать приложения (предполагается, что вы не будете внезапно начинать запись / воспроизведение музыки / что угодно, когда ваше приложение находится в фоновом режиме),
В документах говорится, что "аудио" позволяет воспроизводить звук в фоновом режиме, но, вероятно, это также относится к записи звука. Если это не работает, есть несколько вещей, которые вы можете попробовать:
- Установите оба "voip" и "аудио".
- Воспроизведение тишины (это может быть проще всего сделать с помощью Audio Queue API).
У вас есть "applicationDidEnterBackground:" в вашем делегате приложения. Я почти уверен, что где-то читал (что не могу найти), что вам нужно определить его, чтобы ios распознал, что вы поддерживаете фоновые режимы. Вам не нужно ничего реализовывать в этом.
например
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}