必须成对出现的两个函数,而且,就在快要结束前的evnts handler 中调用后者
m_bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{
[[UIApplication sharedApplication] endBackgroundTask:m_bgTask];
m_bgTask = UIBackgroundTaskInvalid;
=====beginBackgroundTaskWithExpirationHandler:
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handleriOS (4.0 and later)Marks the beginning of a new long-running background task.handler: A handler to be called shortly before the application’s remaining background
time reaches 0.
A unique identifier for the new background task.
endBackgroundTask:
Marks the end of a specific long-running background task.
Parameters
- identifier
-
An identifier returned by the
beginBackgroundTaskWithExpirationHandler:
method.
Discussion
You must call this method to end a task that was started using thebeginBackgroundTaskWithExpirationHandler:
method. If you do not, the system may kill your application.
This method can be safely called on a non-main thread.
Availability
- Available in iOS 4.0 and later.
========
My App Requirement: I should maintain a socket connection to trigger local notification on server push without
using Push Notification(APNs) for some reasons. So i'm using the VOIP background capability of iphone to maintain socket connection.
1. I have configured a stream for VOIP in order to persist socket connection to run in background, so what Timeout value should
i set?, will the socket connection terminates once the timeout expires?, how do i make my application to listen to the socket all the time.?
Client stream configuration is as follows,
NSString *urlStr = @"http://192.168.0.108"; NSURL *website = [NSURL URLWithString:urlStr]; CFReadStreamRef readStream; CFWriteStreamRef writeStream; CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 1234, &readStream, &writeStream); CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); NSInputStream *inputStream = (NSInputStream *)readStream; NSOutputStream *outputStream = (NSOutputStream *)writeStream; [inputStream setDelegate:self]; [inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; [outputStream setDelegate:self]; [outputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [inputStream open]; [outputStream open];
2. should i reconnect the stream in the handler applicationDidEnterBackground:
[[UIApplication sharedApplication] setKeepAliveTimeout:86400 handler:^(void) { if (inputStream) [inputStream close]; if (outputStream) [outputStream close]; urlStr = @"http://192.168.0.108"; website = [NSURL URLWithString:urlStr]; CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 1234, &readStream, &writeStream); CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); inputStream = (NSInputStream *)readStream; outputStream = (NSOutputStream *)writeStream; [inputStream setDelegate:self]; [inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; [outputStream setDelegate:self]; [outputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType] ; [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [inputStream open]; [outputStream open]; }];
3. Say My server restarts and the app is in background how do i ensure the connection? If the Wi-Fi connection
in my iphone or if i terminate the server app the connection will be closed, so what measures should i take to make my app work as expection?
You also need to ensure that you have set the in your pList file
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
</array>
The socket will be managed by the iOS while your application is in the background. Your application will receive the CPU time as soon there is a data available in the socket. So in the runLoop I am checking ht
In my case the signaling protocol is working in a separate thread, so I am spinning the runLoop my self
// Start runloop
while (!m_needStop)
{
CFRunLoopRun();
}
And stopping it when needed:
m_needStop = true;
{
QAutoLock l(m_runLoopGuard);
if ( m_runLoop != NULL )
CFRunLoopStop(m_runLoop);
}
For the sockets in runLoop I have setup the handler functions before scheduling them into the runLoop:
int nFlags = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventCanAcceptBytes | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
CFStreamClientContext context;
context.info = this;
context.version = 0;
context.release = NULL;
context.retain = NULL;
context.copyDescription = NULL;
if ( !CFReadStreamSetClient(m_readStream, nFlags, NotificationProtocolHandler::ReadStreamCallback, &context) )
{
ReleaseStreams();
return false;
}
if ( !CFWriteStreamSetClient(m_writeStream, nFlags, NotificationProtocolHandler::WriteStreamCallback, &context) )
{
ReleaseStreams();
return false;
}
These are the functions which will be called when your socket will has some info for you and even if your application in the background:
void NotificationProtocolHandler::ReadStreamCallback(CFReadStreamRef stream,
CFStreamEventType eventType,
void *clientCallBackInfo)
{
NotificationProtocolHandler* handler = (NotificationProtocolHandler*)clientCallBackInfo;
switch (eventType)
{
case kCFStreamEventOpenCompleted:
break;
case kCFStreamEventHasBytesAvailable:
handler->ProcessInput();
break;
case kCFStreamEventErrorOccurred:
handler->ProcessConnectionError();
break;
case kCFStreamEventEndEncountered:
handler->ProcessConnectionError();
break;
default:
break; // do nothing
}
}
void NotificationProtocolHandler::WriteStreamCallback(CFWriteStreamRef stream,
CFStreamEventType eventType,
void *clientCallBackInfo)
{
NotificationProtocolHandler* handler = (NotificationProtocolHandler*)clientCallBackInfo