Apple's focus is on user experience, and with each new release of iOS it extends more power and control to the developers while maintaining the usability and availability of the device for the user. In the realm of background multitasking, Apple has made some significant changes by exposing additional API calls as well as altering the way that background activities are handled by way of certain restrictions. These restrictions limit apps from causing the user problems, such as unexpected battery drain or a lag in the response time. For this reason, Apple subjects these restrictions and provides to the developer a strict set of APIs in order to implement features.
Despite these risks, Apple has provided ways for application developers to be able to execute finite tasks in the background prior to being suspended. Also, there are ways that long running background tasks can be run following certain Apple guidelines, such as location updates and background audio. Starting in iOS 4, Apple allowed applications to test if a device supports multitasking and execute a finite task when the application is switched to the background. The background state is an intermediate state prior to the application becoming suspended.
As more apps are created to replace functions normally performed on laptops and desktops, the need for these apps to transfer data increases. Also, the size of the data being transmitted is increasing where a developer may need to decide if the transfer may need to be performed completely asynchronously, such as in the case of a digital book or the download of image assets as in the case of a custom mapping app. Apple has provided mechanisms in iOS 7 accommodate this by providing background fetching and background transferring via new API calls.
A sample project was created to demonstrate the techniques explained in this post. Included in the project are both the service tier and the iOS application. There is an instance of the service hosted by Redhat and their OpenShift service. The iOS project is already configured to use this service instance as demonstration. The sample project can be found here.
A Change To Background Execution
There is a fundamental change in the way that iOS now handles background execution. Instead of allowing background tasks to start and run to completion or simply get terminated by iOS, execution will occur in bursts. The idea behind this is to preserve battery life. When the user either backgrounds an app or locks their screen, they may or may not have additional time to run their background task. Also, the schedule that will be used to perform the background fetches is mostly determined by iOS. iOS will keep task execution at a minimum while the device is locked and tasks will be woken up and allowed to execute in groups. For example, when Mail is ready to check for e-mail or when a notification arrives, iOS will wake up other processes to run for a particular amount of time, then the processes will go quiet again.
Using this scheme, iOS is able to provide better battery life since the device will be quiet for certain periods of time and then handle multiple tasks during each wake up period. This is in contrast to the model for iOS 6 where apps will allowed to run background tasks, even after the user locked their device, and other processes would run given their independent polling cycle without coordination.
The first new API change we'll cover is the background fetch. For this feature, iOS will monitor how the user uses your app and will periodically "wake up" your app in order to perform a fetch. This is an opportunity for your app to retrieve information from a remote service to be used in your app and displayed to the user. This keeps your app data fresh and reduces the amount of time it takes for the user to be able to interact with it.
One important detail to keep in mind is that you as a developer don't have much control as to when iOS will call upon your app to fetch the data. You can set the minimum interval time, but that is all. This minimal interval time tells iOS how frequently it makes sense to perform the fetch. You must set this value since it will default to
UIApplicationBackgroundFetchInternalNone, which tells iOS to never perform a background fetch.
In most circumstances, you will want to set this value to be the minimum, which tells iOS to uses its best judgment as to when to perform the update based on how the user uses the app. In your app, set this value in the
application:didFinishLaunchingWithOptions: method in your
Setting Up Your iOS 7 Project In Xcode 5
First, you need to enable the background mode(s) you wish to use. The two new options are downloading content from the network (fetch) and downloading content from the network in response to a push notification (remote notification). To enable these capabilities, you have two choices, to manually edit the application's Info.plist file or use the new Xcode 5 project settings "Capabilities" menu. I would encourage the later as it is a very easy way to view and manage your apps capabilities. In Xcode 5, click on the project to reveal the project editor, then select the "Capabilities" option at the top.
Xcode 5 project capabilities background modes setting - off
Next, slide the switch to "On" for the 'Background Modes" option.
At the bottom of the list you will see the "Background fetch" and "Remote notifications" check boxes that can you select.
Xcode 5 project capabilities background modes setting - on checked
If you prefer to edit the application's Info.plist file, below is what the key and values will look like.
Xcode 5 project capabilities background modes setting - plist
Here is a view of the XML in the application's Info.plist file
Testing Your App
There are two ways to test your app after implementing background fetching. The two different techniques will allow you to exercise your app from both a cold start as well as simulating an app being woken up from suspension.
The first technique will launch your app into the background, simulating a cold start of your app. There is a bit of setup involved in getting this configured, which I will list below.
First, select the scheme by clicking on the name. By default, a single scheme is created for an app.
Xcode 5 project select scheme
Next, select the "Manage Schemes..." option.
Xcode 5 project select scheme
You now have a modal with a list of your schemes. If you have more than one scheme, highlight the scheme you wish to work with.
Now, click to highlight the scheme and click on the gear icon at the bottom left of the window to expose the "duplicate" option.
Xcode 5 project scheme - duplicate
Click the "duplicate" option and you will expose a window creating a new scheme.
Xcode 5 project scheme - duplicate edit
In the right side window, select the "Options" menu
Xcode 5 project scheme - duplicate edit options selected
Edit the name of the scheme and select the check box for "Background Fetch ... Launch due to a background fetch event"
Xcode 5 project scheme - background fetch checked
Background Transfer Service
In iOS 6, apps could perform transfers while in the foreground and continue for a few minutes if the app is transitioned to the background on its way to being suspended. The time an app had to continue to transfer was limited by time without any specific details as to how long. For OS 7, Apple has provided a new API to allow apps to have iOS manage their large downloads and uploads. There are no time restrictions as was present in iOS 6, and the requests can be enqueued either from the foreground or the background. iOS handles most aspects of the transfer and will wake up the app to handle particular details like authentication and errors.
The main API for the background transfer service is the
NSURLSession class, new to iOS 7, replacing the
NSURLConnection. The use the
NSURLSession, you create an
NSURLSessionConfiguration, which will set attributes like HTTP header values, authentication, set cache policies, etc. Then, you can use
NSURLSessionTasks to perform your work. There are session tasks for uploading and downloading, coordinate by the
An important detail about using the
NSURLSessionTasks is that iOS will take over handling your long running network download or upload, even after your app has terminated or been set as suspended. There are additional callbacks you need to implement in your app so that when your app is started or woken up, you can reconnect with the
NSURLSession to obtain the response the data.
application<span class="sy0">:</span>handleEventsForBackgroundURLSession<span class="sy0">:</span>completionHandler<span class="sy0">:</span>
Through the completion handler you will be reconnected to the NSURLSession object to perform any work you need to in your app.
application<span class="sy0">:</span>didFinishLaunchingWithOptions<span class="sy0">:</span> application<span class="sy0">:</span>handleEventsForBackgroundURLSession<span class="sy0">:</span>completionHandler<span class="sy0">:</span>
In keeping with the theme of battery conservation, the background transfer service has a notion of being "discretionary". By default, all background transfers run in discretionary mode, which tells iOS not to run the task if the battery is low or only cellular data service is available.
If the user explicitly quits the app from the multi-tasking card view, background fetching and downloading will not occur until the user launches the app again.
Remote Notifications For Background Fetching
This feature is new to iOS 7 and uses the same Apple Push Notification System (APNS) that existed in iOS 6. To use this background capability, you must include the mode "remote-notification" in your selection or list of
UIBackgroundModes in the application's
Info.plist. In the payload of the APNS message, you include the key/value pair of
content-available : 1.
In order to send a silent remote notification, you will leave out of the APNS payload the "alert", "sound", and "badge" key/value pairs. One important note about silent remote notifications is that they are rate limited. The big question here is what is considered an acceptable rate before the notifications are spooled on the server for later delivery? Apple has not revealed any specific information about a rate or per hour limit, but during the WWDC 2013 talk discussing the new multitasking API, the speaker mentioned that a couple notifications an hour is acceptable and will be delivered immediately. If the rate is determined to be "too high", the push notification will be stored on the server for later delivery. Apple will deliver these pushes when other interaction with the device is performed, such as a push notification for a different app.
With the availability of iOS 7, Apple has provided new features in the API to allow developers to create more responsive apps with up-to-date data. For developers that create apps that display data to the user, consider using the background fetch API to keep the data refresh. If you would rather implement more of a "push" model to your background fetching, consider using silent push notifications that will trigger your app to perform a background fetch, just keep in mind there will be throttling should Apple consider your push requests too frequent.
For developers that may be uploading or downloading large sets of data in their apps, consider using the background transfer service APIs to allow long running transfers to continue long after the app been suspended or terminated. Check out a sample project found here.