A lot of app functionalities can run in the background. However, nowadays mobile devices still come with a limited amount of RAM. The working memory has to be shared with the operating system and other apps running on the device. Mobile devices also come with relatively small batteries. Performing actions in the background may reduce the battery time of these devices and could cause your app to look bad, because it shows up high in the list of battery consuming apps. So, when you run in the background, managing resources is important. This post will show you how to manage resources for background processes in iOS.
There are various reasons why you would want to run your app in the background. Most of the time your app will be paused by iOS, so your app cannot do anything. However there are some exceptions that allow your app to be temporarily unpaused. Your app doesn’t even have to specify a background mode in some of those cases. These exceptions include:
- Just after being moved to the background by the user while a background task is still active. iOS will allow you to finish your task up to a certain amount of time.
- Received a geofence trigger or a significant location update. When the user granted your app permission to use location services in the background, you don’t need a background mode to receive these events.
- Received a beacon trigger. The same is true for beacon region triggers, when the user granted your app permission to use the location in the background, you don’t need a background mode to receive these events.
- App background refresh (requires background mode)
- Remote notification (requires background mode)
The number of possible reasons to run in the background increases over time with every iOS release. Whether it is to ensure that the newest content is already loaded in the app before the user opens the app or to directly perform an action when something happens, background activities are getting more common. So ensuring your app works correctly and efficiently when it gets some execution time while it is in the background is also getting more important.
The first question you should ask yourself is, do I have to execute this specific action at all when the app isn’t in the foreground. For example, updating the UI while the user doesn’t have your app open is a waste of CPU resources. When your answer is no, then you should ensure that what you’re doing is stopped when you move to the background. This also includes polling for device location and ranging for beacons. When the answer is yes, then you have to perform the action as efficient as possible to prevent your app from consuming a lot of battery.
Moving to the background
When the user decides it is time to move on and stop using your app for now, he presses the home button. Your app gets some time to finish its background tasks and then iOS will pause your app. It is good practice to at that point pause your timers and other forms of continuous processing.
You can detect whether your app is about to move to background by subscribing to the method
applicationDidEnterBackground: in your appDelegate. You could also listen for the
UIApplicationDidEnterBackgroundNotification notification. Once your app moves back to the foreground the
applicationDidBecomeActive: method is called. This allows you to reinstate your timers and load stuff back into memory.
When you have one or more background modes it becomes even more important to halt actions when the app moves to the background. For example when your app has the location background mode it may continue to poll the location of the device in the background. However, since you get execution time for processing those location polls, all other activities in your app will then also get the chance to continue in the background. This may increase the battery usage of the device and as a result cause your app to look bad in the battery statistics screen.
It is also possible that iOS starts your app to run directly in the background. The user then didn’t tap on your app icon and no UI will become visible. Reasons for this to happen could be the same as mentioned in the introduction. This could be just after the device has booted or after your app has been killed earlier to free up memory for other apps.
When your app starts in the background you often have to initialize less than when the app would appear in the foreground. A mistake we often see our customers make is to log this initialization as an app open in their analytics suite, causing the number of active users shown to become way too high. Then every time the app starts in the background it is counted as a session, while the user hasn’t performed a single action in your app. Also you don’t have to refresh the content of your views yet as the user won’t have a look at it anyway. This may prevent high unnecessary server load.
You can detect whether the app is in the background by checking whether
[UIApplication sharedApplication].applicationState is equal to “
UIApplicationStateBackground”. When this is the case your app is running in the background. Otherwise your app is running in the foreground or will move to the foreground. When started in the background, your app will be informed with the
applicationDidBecomeActive: appdelegate call when your app moves to the foreground, similar to the call when being moved to the background.
In the end, most of the time it is not that much work to make your app function correctly when running in the background. Because iOS will pause your app most of the time when your app is in the background, most mistakes won’t result in large issues for the end user. It may cost you some extra backend load or some statistics may end up incorrect, but the end user may not even notice. The risks become higher when your app also does some background tasks. Then problems could become noticeable.
An example: what happens when you integrate the Plot Plugin?
The Plot plugin is a library that provides location based notifications. This means that once a user enters an area, a geofence, a notification can be sent. The Plot plugin achieves this by using the functionality of the LocationManager class of iOS provides. Let’s show what happens:
A user downloads and installs your app. After installation the app is opened. The app asks to opt-in for location services and an opt-in for sending notifications, which the user then complies to. The Plot Plugin, which is integrated into your app, then starts monitoring for geofence regions nearby. The user looks at a couple screens of your app and then presses the home button to move on to another app. iOS will now pause your app. When the user would tap on your app icon again, it can quickly reopen the app and the user can continue where he left off.
While in the app is in the background, the user moves with his device into the geofence area that the Plot Plugin just started monitoring for. iOS will now resume the app and will give the app some execution time to run the region callback. In this callback a notification is sent. iOS now pauses the app again.
A couple days later the user enters another area that is monitored by a geofence. The app has been stopped by iOS to free memory earlier. In this instance iOS will start the app again without showing the UI of that app. The region callback will be called straight away and afterwards the app will be paused.
If your app still had some other scheduled work when the app was unpaused, for example using timers, those would now run as well. This is probably not what you wanted, since the UI won’t be loaded and the tasks performed wouldn’t have a noticeable effect for the user. The resources used for that are basically wasted. Therefore pause your timers and stop other scheduled work when your app moves or starts in the background.
Got curious what location based notifications could bring to your app? Have a look at our website to see what we offer.