How To Test Background Fetch Ios
Update note: Brody Eller updated this tutorial for Xcode 10 and Swift four.two. Chris Wagner wrote the original.
Way dorsum in 2010 with iOS four, Apple introduced multitasking.
Developers and users alike are often confused as to what the iOS multitasking system allows. Apple tree has restrictions in place for the use of background operations in an effort to improve user experience and extend battery life. Your app is only allowed to continue running in the background in very specific cases. For example, these include playing sound, getting location updates or fetching the latest content from a server.
If your task does non fall into these categories, backgrounding may not be for you. You may even detect yourself with an App Store rejection if you try to cheat the organization by using background modes outside the realm of their purposes, so consider yourself warned!
Getting Started
You can download the project files at the top or bottom of the tutorial past clicking on the Download Materials push. You'll find the user interface and some of the logic that is not directly applicable to the topic has been provided for y'all.
Before excavation into the project, here's a quick overview of the basic background modes available in iOS. In Xcode, you can run across the listing by pulling up the Capabilities tab of your app target. It looks like this:
To get to the groundwork modes capability list y'all:
- Select the projection from the Projection navigator.
- Click the app target.
- Select the Capabilities tab.
- Plow the Background Modes switch on.
In this background modes tutorial, you lot'll investigate iv ways of doing groundwork processing:
- Play audio: The app can continue playing and/or recording audio in the background.
- Receive location updates: The app can continue to get callbacks every bit the device'south location changes.
- Perform finite-length tasks: The generic "whatever" case, where the app can run arbitrary code for a limited amount of time.
- Background Fetch: Become updates to the latest content scheduled by iOS.
If you're simply interested in one or several of these modes, experience gratis to skip around!
Before you can run the projection, y'all must fix your development team, as shown here:
Run the sample project to get a feel for information technology. At that place are four tabs — one to cover each fashion:
Note: For the total event, yous should follow forth on a real device. If you forget a configuration setting, the app might appear to run fine in the groundwork on the simulator; notwithstanding, when y'all switch to a existent device, it may not work at all.
Playing Audio
First up, background audio.
There are several ways to play audio on iOS and about of them require implementing callbacks to provide more audio data to play.
If you want to play audio from streaming data, you lot can start a network connectedness, and the connectedness callbacks provide continuous sound information.
When you activate the Audio background mode, iOS will continue these callbacks fifty-fifty if your app is not the current active app. That's right — the Audio background manner is virtually automatic. Yous simply have to activate it and provide the infrastructure to handle it accordingly.
Open AudioViewController.swift.
The app makes use of an AVQueuePlayer
to queue up songs and play them ane later the other. The view controller is observing the histrion'southward currentItem
value to provide updates.
Giving Credit Where Credit Is Due
The starter projection includes audio files from incompetech.com, a favorite royalty-gratuitous music website. With credit given, y'all can use the music for free. Then, here you lot get:
- "Feelin Proficient" Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/ - "Fe Bacon" Kevin MacLeod (incompetech.com)
Licensed under Creative Eatables: Past Attribution iii.0 License
http://creativecommons.org/licenses/by/three.0/ - "What You Desire" Kevin MacLeod (incompetech.com)
Licensed nether Creative Commons: By Attribution three.0 License
http://creativecommons.org/licenses/by/3.0/
Cheers, Kevin!
When the app is in the active state, it shows the music title characterization and, when in the background, it prints the title to the console. The label text could withal update while in the background, merely the betoken here is just to demonstrate that your app continues to receive this callback when your app is in the background.
Build and run, and you lot should see this:
Now tap Play and the music will get-go.
Testing Audio in the Background
While running on an bodily device, tap the Home button and the music will stop. Why? Well, in that location's all the same a very crucial slice missing!
For virtually background modes (the "Whatever" mode is the exception), you need to enable the capability to indicate that the app wants to run code while in the background.
Return to Xcode and practice the following:
- Click the project in the Projection navigator.
- Select TheBackgrounder target.
- Click on the Capabilities tab.
- Scroll down to Background Modes and plow the switch on.
- Check Audio, AirPlay and Picture in Picture.
Build and run again. Kickoff the music and tap the Dwelling house button. This time you lot should still hear the music, even though the app is in the background.
You should likewise see the time updates in your Console output in Xcode, proof that your code is still working even though the app is in the background.
Wow, if you already accept an audio player in place, playing audio in the background is easy! Well, that's ane mode downward. If you're post-obit through the entire background modes tutorial, three modes to become!
Receiving Location Updates
When in Location background way, your app volition still receive location delegate messages with the updated location of the user, fifty-fifty when the app is in the background. You can control the accuracy of these location updates and even change that accuracy while the app runs in the background.
The second tab is for location updates, so open LocationViewController.swift.
In this controller, you'll observe that CLLocationManager
runs the show. To receive location information, you create and configure a CLLocationManager
instance. In this case, the app monitors location when the user activates an on-screen UISwitch
. As information technology receives location updates, the app draws pins on a map. When the app is in the groundwork, you should see the log of location updates in your console output in Xcode.
Enabling Location Updates
An important line to note is requestAlwaysAuthorization()
on the CLLocationManager
instance. This is a requirement since iOS viii, and it brings upward a dialog asking for permission to receive locations in the background.
Now that you're familiar with groundwork modes, you don't need to brand the same mistake as before! Check the box for Location updates to let iOS know that your app wants to go on receiving location updates while in the background.
In addition to checking this box, iOS 8 and above requires that you fix a primal in your Info.plist explaining to the user why you need background updates. If you don't include this, location requests will silently fail. The starter projection already has these keys added. To notice them:
- Select the project in Xcode.
- Click the Info tab for TheBackgrounder target.
- Look for the keys named Privacy — Location Always and When In Apply Usage Description and Privacy — Location When In Use Usage Clarification.
- Write a convincing description of why you need to receive location updates in the groundwork.
Now, build and run! Switch to the second tab and flip the switch on the superlative left corner to ON.
When you do this the first fourth dimension, y'all'll see the message that you wrote into your location privacy reason. Tap Always Let and go for a walk outside or around your building (endeavour not to get too distracted catching Pokemons). Yous should start seeing location updates, fifty-fifty on the simulator.
After a while, you should see something like this:
Testing Location Manner in the Background
If you background the app, you should run into the app updating the location in your console log. Open the app once more and you'll see that the map has all the pins for the locations that were updated while the app was in the background.
If you're using the simulator, you tin can use information technology to simulate movement, too! Check out the Debug ▸ Location carte du jour:
Easy peasy, right? On to the 3rd tab and the third groundwork style!
Performing Finite-Length Tasks… or, Whatever
The next background way is officially called Executing a Finite-Length Job in the Background. What a mouthful. Whatever is a fleck catchier!
Technically, this is non a background way at all, as yous don't have to declare that your app uses this mode in Capabilities. Instead, information technology'due south an API that lets yous run arbitrary code for a finite amount of fourth dimension when your app is in the background. Well… whatever!
When to Perform Finite-Length Tasks
A very valid use case of the Whatever background style is to complete some long running task, such equally rendering and writing a video to the photographic camera coil.
Just this is but one example. Every bit the lawmaking you tin run is arbitrary, you can utilise this API to do pretty much anything: Perform lengthy calculations (which is what y'all'll practice in this tutorial), employ filters to images, return a complicated 3D mesh… whatever! Your imagination is the limit, as long as you continue in mind that you only get some time, not unlimited time.
iOS determines how much time you go after your app moves to the background. There are no guarantees on the fourth dimension you're granted, only you lot tin always check backgroundTimeRemaining
on UIApplication.shared
. This will tell you how much time you take left.
The full general, observation-based consensus is that you go iii minutes. Over again, there are no guarantees and the API documentation doesn't even give a ballpark number — so don't rely on this number. You might go v minutes or 5 seconds, so your app needs to exist prepared for… any!
Here'due south a mutual job that every CS student should be familiar with: calculating numbers in the Fibonacci Sequence. The twist hither is that you lot'll calculate these numbers in the background!
Setting Up a Finite-Length Job
Open up WhateverViewController.swift and take a look at what'southward in that location already. As information technology stands, this view volition calculate Fibonacci numbers in sequence and display the consequence. If y'all were to suspend the app on an actual device, the calculations would stop and option upward where they were once the app became active again. Your task is to create a groundwork task then that the calculation can keep running until iOS says, "No more than!"
Y'all first need to add the post-obit belongings to WhateverViewController
:
var backgroundTask: UIBackgroundTaskIdentifier = .invalid
This property identifies the task request to run in the background.
Adjacent add the following methods to WhateverViewController
:
func registerBackgroundTask() { backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in self?.endBackgroundTask() } assert(backgroundTask != .invalid) } func endBackgroundTask() { impress("Background task ended.") UIApplication.shared.endBackgroundTask(backgroundTask) backgroundTask = .invalid }
registerBackgroundTask()
tells iOS that you need more than time to complete whatever it is that you're doing in example the app moves to the background. After this phone call, if your app moves to the background, it will still get CPU time until you phone call endBackgroundTask()
.
Well, almost. If you don't telephone call endBackgroundTask()
after a period of fourth dimension in the background, iOS will telephone call the closure divers when you chosen beginBackgroundTask(expirationHandler:)
to give yous a take chances to stop executing code. And then it's a very good idea to then phone call endBackgroundTask()
to tell the OS that y'all're done. If you don't do this and you lot continue to execute code afterwards this cake runs, iOS will terminate your app!
Registering & Ending Background Tasks
Now, for the important office. You lot need to update didTapPlayPause(_:)
to register the background task and end it. There are two comments in this method where you'll add some code.
Call registerBackgroundTask()
below the "register background task" annotate:
registerBackgroundTask()
You at present call registerBackgroundTask()
when calculations brainstorm and then you tin continue calculating numbers in the background.
At present, add together the post-obit cake beneath the "terminate background task" comment:
if backgroundTask != .invalid { endBackgroundTask() }
At present, when the user stops calculations, you call endBackgroundTask()
to indicate to iOS that yous don't need any actress CPU fourth dimension.
Information technology's important that you call endBackgroundTask()
for every time yous call beginBackgroundTask(expirationHandler:)
. If yous phone call beginBackgroundTask(expirationHandler:)
twice and only telephone call endBackgroundTask()
for one of the tasks, y'all're still going to get CPU time until yous call endBackgroundTask()
a 2d fourth dimension with the second background chore'due south identifier. This is also why you need backgroundTask
.
Updating the User Interface
At present update the calculateNextNumber()
method to behave differently based on the app'southward state.
Supervene upon the final line, resultsLabel.text = resultsMessage
, in the method with the following:
switch UIApplication.shared.applicationState { case .active: resultsLabel.text = resultsMessage example .background: print("App is backgrounded. Side by side number = \(resultsMessage)") print("Groundwork time remaining = " + "\(UIApplication.shared.backgroundTimeRemaining) seconds") case .inactive: pause }
Yous update the label merely when the app is active. When the app moves to the background, you print a message to the panel instead, stating the new effect and how much groundwork fourth dimension remains.
Build and run, then switch to the third tab.
Tap Play and you should meet the app calculating the values. Now, tap the Habitation button and watch the output in Xcode's panel. You should see the app yet updating the numbers while the time remaining goes down.
In near cases, this time will start with 180 (180 seconds = 3 minutes) and go downward to v seconds. If you expect for the fourth dimension to expire when y'all reach five seconds (it could be another value depending on your specific conditions), iOS invokes the expiration cake and your app should stop generating output. And then, if y'all go dorsum to the app, the timer should start firing once again and the whole madness will go along.
Treatment Timer Expiration With Backgrounding
There'due south only one problems in this code. Suppose you lot background the app and look until the allotted time expires. In this case, your app will call the expiration handler and invoke endBackgroundTask()
, thus ending the need for background time.
If you then return to the app, the timer volition continue to burn. Merely if y'all leave the app again, you'll become no background time at all. Why? Because nowhere between the expiration and returning to the background did the app phone call beginBackgroundTask(expirationHandler:)
.
How can you solve this? There are a number of ways to become well-nigh information technology and one of them is to utilize a land change notification.
You tin can meet all the details on how to respond to state change in Apple tree's documentation for Execution States for Apps.
Fourth dimension to fix the problems. First, add a new method named reinstateBackgroundTask()
:
@objc func reinstateBackgroundTask() { if updateTimer != nil && backgroundTask == .invalid { registerBackgroundTask() } }
You just demand to reinstate if there is a timer running and the background task is invalid. Breaking your code into smaller utility functions that do ane thing is paying off. In this case you but need to call registerBackgroundTask()
.
Now, override viewDidLoad()
and subscribe to UIApplicationDidBecomeActiveNotification
past adding the post-obit:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default .addObserver(self, selector: #selector(reinstateBackgroundTask), proper noun: UIApplication.didBecomeActiveNotification, object: cypher) }
This tells iOS to call your new method reinstateBackgroundTask()
whenever the awarding becomes active.
Whenever you lot subscribe to a notification, you should also think well-nigh where to unsubscribe. Use deinit
to do this. Add the post-obit:
deinit { NotificationCenter.default.removeObserver(self) }
Notation: While iOS no longer requires you to remove your observer, it's still skillful practice to do so.
And there yous accept it; you lot tin now do whatever you lot want, at least for equally long every bit iOS says that it'southward OK.
On to the last topic for this groundwork modes tutorial: Background Fetching.
Background Fetch
Background fetch is a mode introduced in iOS seven that lets your app announced always up-to-date with the latest information while minimizing the impact on battery life. Suppose, for example, yous were implementing a news feed in your app. Prior to background fetch, you might practise this by getting new data in viewWillAppear(_:)
.
The problem with this solution is that your users are looking at erstwhile data for at least several seconds until the new information comes in. Wouldn't it be better if, when they opened your app, the new information were magically there? This is what background fetch gives you.
When enabled, the system uses usage patterns to determine when to best fire off a groundwork fetch. For instance, if your user opens the app at 9 AM each forenoon, information technology's probable that a background fetch volition occur one-time before that time. The organization decides the best time to issue a background fetch and for this reason you should not utilize it to practice critical updates.
Setting Up a Groundwork Fetch
In order to implement background fetch, there are three things yous must do:
- Cheque the box Background fetch in the Background Modes of your app's Capabilities.
- Apply
setMinimumBackgroundFetchInterval(_:)
to fix a time interval appropriate for your app. - Implement
application(_:performFetchWithCompletionHandler:)
in your app delegate to handle the background fetch.
As the name implies, background fetch normally involves fetching data from an external source like a network service. For the purposes of this background modes tutorial, you'll fetch the current fourth dimension and won't utilise the network.
In contrast to finite-length tasks, yous but take seconds to operate when doing a background fetch — the consensus figure is a maximum of 30 seconds, but shorter is amend. If you need to download large resources as part of the fetch, this is where y'all demand to use URLSession
'south background transfer service.
Implementation Details
Fourth dimension to go started. First, open FetchViewController.swift and take a look at what this does.
The fetch(_:)
method is a simplified replacement of what yous might actually do to fetch some data from an external source (such as a JSON or XML RESTful service). Since it might have several seconds to fetch and parse the data, you laissez passer a completion handler that you telephone call when the process finishes. Yous'll see why this is important a little later.
updateUI()
formats the time and shows information technology. The guard
statement around updateLabel
is to ensure that the view is actually loaded. fourth dimension
is an optional type then if it isn't set, information technology shows the message "Not updated yet."
When the view first loads, you lot don't fetch just go direct to updateUI()
, which ways the bulletin "Not yet updated" appears first. Finally, when the users taps Update, it performs a fetch and, in its completion handler, updates the UI.
The view controller works; there's nil you lot need to do to it.
However, background fetching is non enabled.
Step I to Enabling Background Fetch
The first stride to enabling background fetching is to check Background fetch in the Capabilities tab of your app. By at present, this should be old chapeau. Get ahead and practice this.
Step Two to Enabling Groundwork Fetch
Side by side, open AppDelegate.swift and add the following to application(_:didFinishLaunchingWithOptions:)
:
UIApplication.shared.setMinimumBackgroundFetchInterval( UIApplication.backgroundFetchIntervalMinimum)
This requests groundwork fetches by setting the minimum groundwork fetch interval. The default interval is UIApplicationBackgroundFetchIntervalNever
, which you might want to switch back to, if, for example, your user logs out and no longer needs updates. You can besides set a specific interval in seconds. The system will look at least that many seconds before issuing a groundwork fetch.
Be careful non to set up the value likewise small considering it may chew through battery unnecessarily besides as hammer your server. In the end, the exact timing of the fetch is up to the system simply will await at to the lowest degree this interval before performing information technology. By and large, UIApplicationBackgroundFetchIntervalMinimum
is a good default value to employ.
Step Three to Enabling Groundwork Fetch
Finally, to enable groundwork fetch, you must implement application(_:performFetchWithCompletionHandler:)
. Add that now to AppDelegate
:
// Support for background fetch func application( _ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { //i if permit tabBarController = window?.rootViewController as? UITabBarController, let viewControllers = tabBarController.viewControllers { //2 for viewController in viewControllers { if let fetchViewController = viewController as? FetchViewController { //3 fetchViewController.fetch { //iv fetchViewController.updateUI() completionHandler(.newData) } } } } }
Here's what's going on above:
- Optionally cast the
rootViewController
as aUITabBarController
since therootViewController
is not necessarily ever as aUITabBarController
in every app. However, therootViewController
is always aUITabBarController
in this app, which ways this piece of code will never fail. - Loop though all of the view controllers in the tab bar controller and find the one that successfully casts to
FetchViewController
. In this app, you know it's the last view controller then you could hard-code it, but looping makes it a little more robust in case y'all decide to add or remove a tab after. - Telephone call
fetch(_:)
. - When
fetch(_:)
completes, update the UI and then telephone call thecompletionHandler
that was passed in as a parameter. It's important that you telephone call this completion handler at the end of the functioning. You specify what happened during the fetch as the first parameter. Possible values are.newData
,.noData
and.failed
.
For simplicity, this tutorial always specifies .newData
since getting the time will never fail and is ever different than the last call. iOS tin can then use this value to better time the groundwork fetches. The system knows, at this point, to take a snapshot of the app so that it can present it in the card view of the app switcher. And that's all there is to it.
Note: Rather than passing the completion closure along, it can be tempting to salvage it away in a property variable and telephone call that when your fetch completes. Don't do this. If you get multiple calls to awarding(_:performFetchWithCompletionHandler:)
, the previous handler volition be overwritten and never chosen. It's better to pass the handler through and call it as it makes this kind of programming error impossible.
Testing Background Fetch
One way to test groundwork fetch is to sit down around and wait for the system to decide to do it. That would require a lot of sitting. Fortunately, Xcode gives a way to simulate a background fetch. At that place are 2 scenarios you need to test. One is when your app is in the background and the other when your app is coming back from being suspended. The first way is the easiest and is just a menu selection.
Testing When the App Is Resumed From Suspension
There is a launch option that lets y'all launch your app directly into suspension. Since you might desire to test this semi-often, information technology's best to make a new Scheme with that pick always gear up. Xcode makes this easy.
Outset, select the Manage Schemes option.
Next, select the only scheme in the list, and then click on the Gear icon and select Duplicate.
Lastly, rename your scheme to something reasonable, like "Background Fetch," and bank check the checkbox to Launch due to a background fetch event.
Run your app with this scheme. You'll detect that the app never actually opens merely is launched into a suspended state. Now, manually launch it and go to the Fetch tab. You should see that there is an updated time when you launched the app instead of "Not all the same updated."
Using Background Fetch mode effectively lets your users seamlessly get the latest content.
Where to Become From Here?
You tin can download the completed project files by clicking on the Download Materials button at the pinnacle or bottom of the tutorial.
If you lot want to read Apple's documentation on what y'all covered here for groundwork modes, the best place to start is in Background Execution. This documentation explains all background modes and has links to the appropriate section of the documentation for each one.
A particularly interesting department of this document is the one that talks about being a responsible background app. There are some details that might or might not relate to your app here that yous should know before releasing an app that runs in the groundwork.
Finally, be sure to cheque out URLSession if you plan on doing large network transfers in the background.
We hope you enjoyed this tutorial on groundwork modes and, if you lot have any questions or comments, delight bring together the forum discussion beneath!
How To Test Background Fetch Ios,
Source: https://www.raywenderlich.com/5817-background-modes-tutorial-getting-started
Posted by: wrightsagessay.blogspot.com
0 Response to "How To Test Background Fetch Ios"
Post a Comment