Keep Your iOS App Running in Background Forever

I’ve known many people in my life who have a nasty habit of leaving stuff they’re not using plugged into the wall, just wasting energy. My wife would be a prime example. She’s just not in the habit of unplugging it and changing your habits can be hard. Thus, I set out to create an iOS app to remind her to unplug the charger from the wall every time she unplugs the device from a power source.

One without knowledge of iOS development would imagine this to be a simple task. The logic is certainly simple. Notice the battery state go from “charging” or “full” to “unplugged?” Great, send a simple local notification. Otherwise, just keep monitoring the battery state. So what’s the issue? Apple doesn’t want to keep apps running in background.

The logic behind this is pretty reasonable. Apps running in the background drain battery life faster. Apps draining your battery life gives you a bad perception of the device, not the app, because the average consumer has no idea that it’s an app, yet alone which specific app, that’s making their battery life crappy. Thus, iOS won’t let your app run in the background but it does give you some options, such as push notifications, to provide some data to the user and prompt them to open the app again to get the full details.

This is reasonable, but the problem is that push notifications are driven by data coming from the internet. What if you just want to monitor something on the device (i.e. battery state)? Well, as far as I can tell you’re out of luck without using a hack.

The notable hacks are using location services, playing an inaudible sound, and VOIP. Location services really can drain your battery as GPS is power hungry. Playing an inaudible sound is a good option but your app’s going to die if you actually use your device to play audio/video (and most of us do). So the only option in my mind is to use the VOIP hack.

The logic behind allowing VOIP apps to run in the background forever is that they need to be able to receive calls at all times. Thus, generally iOS tries not to close these apps and as a failsafe if it does (due to running out of memory or a crash or just restarting your device) it’ll automatically relaunch it in the background without making the user do anything.

The VOIP hack takes advantage of this to work with any application that wants to run in the background forever. There’s scattered information online, particularly on stack overflow on how to do this but it’s poorly documented and I couldn’t even get it to work for my application without some changes. Thus, I wanted to put it out here as clearly as possible to help anyone else working on an application like mine that needs to monitor the device in the background.

The configuration:
The first thing you need to do is modify your app’s plist. Add the following settings.

  • Application does not run in background: NO
  • Required background modes: VOIP

This lets iOS know that your app will be running in the background and thus will ensure that if it’s terminated, iOS restarts it automatically for you.

The code:
First, we need to set up the code for when the application launches. In here we set up our background task (bgTask) and the block that’s called when our background task expires after 10 minutes (expirationHandler). The expiration handler block ends our background task and restarts it. Additionally, you’ll notice that we start the background task immediately (even if we’re about to go into active mode) because when the app is terminated and relaunched by iOS it doesn’t tell the app that it’s going into background mode.

Next, we set up the background job. The key piece here is the dispatch_async block. This is the work we’ll be doing in the background. In my case, the work is just a while loop that checks the battery and then sleeps for 1 second. For 10 minutes this while loop executes and then we see the expiration handler called.

What’s interesting is that even though the expiration handler is ending our task, the dispatch_async block keeps running. Thus, we set a flag in the expiration handler saying the job has expired and use that to trigger the while loop’s end. Finally, we have the expiration handler spin while it waits for the old job to do this and exit the dispatch_async block. If you don’t do this you’ll have multiple dispatch_async blocks running at once and your app will be terminated more quickly.

Lastly, remember that we started the background task as soon as the app launched. If you don’t want this to run when the app is active then do something in applicationDidBecomeActive to stop the task from running. In my case this just meant setting another flag to get the while loop to exit.

That’s it! From my limited testing this seems to work well and not have a huge effect on battery life. Let me know if it works for your app.

The one huge drawback of this approach (as well as any I’m aware of to create this sort of application) is that Apple would reject it from the app store. Thus, if you’re looking to create an app for yourself, your wife, your friends, etc. then this’ll get the job done, but if you want to get it out into the world you’re out of luck.

Thus, I’m doing the best I can by putting my app on GitHub. I’d love any feedback or contributions.

18 thoughts on “Keep Your iOS App Running in Background Forever”

  1. The github project gets updated with new features and fixes. This blog post doesn’t. Not sure why this would be surprising. It’s been 5 months since I wrote this.

  2. Unfortunately no. This did work on iOS6 but somewhere around the 6.01 or 6.02 release Apple broke the hack. Haben’t spent any time trying to figure out a new way around it so I’d be interested in knowing if you find one. Perhaps in iOS7 they’ll allow for something like this in a “legal” way finally.

  3. I can give the short updated on what I was able to figure out.

    It works in general however there are some conditions:
    – your device has to be actively used
    – when your device is not being actively used – after a while (dont know exactly whats the period) it is terminated

    not being actively used means that the device is “turned off”, the display is not in an active mode

    The questions is:

    – is it because in loops there is constantly being checked battery status
    – is it because iOS terminates all processes that it can in order to save battery

    ?

  4. So I think it gets terminated eventually because iOS terminates all processes to save battery, get more memory, etc. However, it’s supposed to respawn the application as soon as it’s killed due to it being marked as a VOIP app. What I don’t understand is why this how now broken.

  5. i want to run my application in background.when it get some Bluetooth signals ,it starts working on foreground.when does not get any signals ,it reenter in background mode.how i can do this?

  6. I’m not sure. As has been discussed the hack I was using to keep it in the background isn’t quite working anymore on the latest version of iOS 6. Additionally, I’m not aware of any way to force an app into the foreground without manual user interaction (although I haven’t really looked into it so there may be some way). What you may be able to do is listen in the background for bluetooth signals and when you get one send a local notification to try to get the user to open the app in the foreground. Just an idea.

  7. Thanks, for the nice tutorial. i have a doubt that in the application we used “Voice over IP” as background mode, but not implemented the “Voice over IP” functionality any where in the application. So here we are using the background mode only to run the app continuously in background with out any functionality regarding the Voice over IP Service.

    Will apple accept these type of apps to App Store?

  8. It may be ok. Are you trying to keep the background process alive forever? If not it’s probably fine. If so, then I’m not sure. Like I said previously, it appears they’ve made the hack to make it run forever stop working in later versions of iOS6 anyhow.

  9. yes, i need to run app continuously in the background, actual requirement of mine is to alert the user when he reaches or about to reach(with in 100 meters ) a predefined location with a sound. for this i am using “”App registers for location updates”” background mode in plist. with this the app is working in background, and i am receiving location updates but the audio is not triggering.

  10. only add [app beginBackgroundTaskWithExpirationHandler:^{}]; in the applicationDidEnterBackground ,
    it seems that it can execute forever!
    It’s so confused that when I add sth on that, like add two long task,it can get some strange outcome.

  11. Probably a bit late, but if you ever created an app like this that you think Apple wouldn’t accept, you can always send it to Cydia for jailbreak users. Costs nothing to send something there and if you make it a paid app you could even make a buck or two (yes, jailbreak user do indeed buy things, contrary to their image).

  12. Hi,

    Does this solutions still work?
    I have this on iOS 7.1, gets killed in 3 minutes.
    Could you please help me.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>