1

I have a voip app and it needs to run in the background. To my understanding these are the things I need to do:

  1. Flag the app as voip.
  2. Set the 'application does not run in background' flag to NO.
  3. Set an expiration handler, a piece of code that extends the standard 10 minutes of execution time you get.
  4. More?

I set both flags in the info.plist file and I get my 10 minutes. I tried what is suggested in this post. Here is my code:

//in didFinishLaunchingWithOptions:
expirationHandler = ^{
    NSLog(@"ending background task");
    [[UIApplication sharedApplication] endBackgroundTask:bgTask];

    NSLog(@"restarting background task");
    bgTask = UIBackgroundTaskInvalid;
    bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];

    NSLog(@"finished running background task");
};

//in applicationDidEnterBackground
NSLog(@"entering background mode");
bgTask = UIBackgroundTaskInvalid;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];

// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // inform others to stop tasks, if you like
    [[NSNotificationCenter defaultCenter] postNotificationName:@"MyApplicationEntersBackground" object:self];

    //this while loop is just here for testing
    inBackground = true;
    while (inBackground) {
        NSLog(@"stayin alive!!"); //this keeps going forever
        sleep(10);
    }
});

The situation:

I use a third party library that handles the communication with our webservice. The service is a CommuniGate pro server. I receive presence updates (online/offline) and instant messages from contacts via the library. The library is CommuniGate's ximss library, a protocol they made which is similar to xmpp and is used for xml-based sip requests, as well as IM and presence. When the user logs in to the app, he sees his contacts (CmmuniGate friends list) and he can choose to call one. After a ximss verification message has been sent and the other side accepted the call it logs the start time of the call and starts a facetime call.

The problem:

When the app enters the background by pressing the home button, I start seeing the 'stayin alive' message in the log and every ten minutes I see that it restarts the background task.
When the app enters the background by pressing the power button, the 'staying alive' messages start showing up for ten minutes, after that it restarts the background task and start restarting it about every 50-100 miliseconds.
I would've been fine with this for now, even it eats battery, because I have time to work on updates and our users don't own the ipads, we do. The problem for me now is that the ximss library loses it's connection (it is session-based). I could restart the session in the library, but this means quite a bit of data transfer to fetch the contacts list and some users use 3g.
I can't edit the library's source, nor can I see it, so I don't know if it creates the sockets the right way.

What do I have to do to handle both situations correctly? I don't even understand why there is a difference.

Community
  • 1
  • 1
Kevin
  • 2,739
  • 33
  • 57
  • 1
    You cannot re-extend the background task when it expires. Also, in iOS 7 background tasks are only 3 minutes which will give you problems. Voip uses a different mechanism to keep your app alive. Once you set the plist entry, iOS should keep your app alive as long as possible for you. – Mike Weller Aug 15 '13 at 07:16
  • @MikeWeller I can re-extend the ten minutes, as I stated, that is not the problem. The problem is how it should be done right. – Kevin Aug 15 '13 at 07:17
  • I think the reason your app is staying alive beyond the 10 minutes is not because you are recreating a background task (which should not work), but because you enabled voip mode in your plist. – Mike Weller Aug 15 '13 at 07:18
  • Look at XMPPFramework, may be you will find something usefull for your case. It seems to work fine in background via sockets. – Denis Kutlubaev Aug 15 '13 at 07:21
  • @MikeWeller If I remove the code I've shown, my ximss session is killed right off. If I add the code again it stays alive. When I use this code and I press the home button it stays alive for hours. When I do the same with the power button it dies after the first ten minutes. – Kevin Aug 15 '13 at 07:22
  • @wzbozon That looks good, but I have to use ximss for the messaging part. – Kevin Aug 15 '13 at 07:23

1 Answers1

-1

You cannot re-extend background tasks like this; your app is likely to be terminated. If this is working, it's because you have the background voip mode enabled, not because you are restarting the background task.

Once you have set the voip plist entry, iOS will attempt to keep your app alive as long as possible and restart it if it does get terminated. From Implementing a VoIP App:

Including the voip value in the UIBackgroundModes key lets the system know that it should allow the app to run in the background as needed to manage its network sockets. An app with this key is also relaunched in the background immediately after system boot to ensure that the VoIP services are always available.

In addition to setting this key, if you need to periodically run code to keep your voip connection alive, you can use the setKeepAliveTimeout:handler: method on UIApplication.

See also Tips for Developing a VoIP App:

There are several requirements for implementing a VoIP app:

  1. 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.

  2. Configure one of the app’s sockets for VoIP usage.

  3. 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.

  4. Configure your audio session to handle transitions to and from active use.

  5. 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.

  6. 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.

Almost all of the documentation you need is on the Apple developer site.

Mike Weller
  • 45,401
  • 15
  • 131
  • 151
  • Like I told you, if I remove the code, the session dies. I set the UIBackgroundModes key, I can't configure the socket myself. It might be that in a normal situation you are right, but this is simply not true for my situation. I just verified that when the code I showed is commented, the session dies immediately after going to the background. – Kevin Aug 15 '13 at 07:31
  • I replaced my code with a setKeepAliveTimeout:handler: and the session stays alive, but I don't get realtime updates now, instead, all presence and IM updates are received when I return to the app. – Kevin Aug 15 '13 at 07:38
  • Consider calling setKeepAliveTimeout:handler: in appDidFinishLaunchingWithOptions rather than in applicationDidEnterBackground. When the device is first booted up, the OS will start your app in the background. It goes through the launch sequence, but since it is in the background already DidEnterBackground is not called. Likewise if your app is restarted. For a VoIP app the user will expect to receive calls without having to have invoked the app themselves. – KHansenSF Oct 31 '13 at 01:18