I'm working on an iOS application and I want the app to terminate after hanging in the background for more than 5 minutes and when the user opens the app again it should display the login. For now the app terminates immediately when it reaches the background and the login screen when the user re-opens the app. I did this by adding a property called "Application does not run in background" to the info.plist file and I set the value to "YES". As I mentioned at the start what I want to do is to terminate the app after 5 minutes in background but not immediately. And the login screen appearing after the user re-opens the app is working fine.
Application does not run in background property in info.plist
I guess you this is managed by the operating system that for how long the app runs in the background, and the os terminates it when it require resources to get free.
A workaround that could be done is, store the time value in UserDefaults whenever the app goes to background, and whenever the app comes foreground, check for the previous time value. If the difference is greater than 5 minutes, you may direct to login.
You can request background time when you are told that you are being suspended. I believe the max you will get is 3 minutes, not 5. That will prevent your app from being terminated, and keep your app getting CPU time during that time. (Which will use extra battery power.) You will get a notice when that time expires, and you can save your app state and log off at that point.
Search on "Extending Your App's Background Execution Time" in the Xcode help system or Apple's docs for more information. The overview section of that document reads:
Overview
Extending your app’s background execution time ensures that you have adequate time to perform critical tasks. For tasks that require more background time, use Background Tasks.
When your app moves to the background, the system calls your app delegate’s applicationDidEnterBackground(_:) method. That method has five seconds to perform any tasks and return. Shortly after that method returns, the system puts your app into the suspended state. For most apps, five seconds is enough to perform any crucial tasks, but if you need more time, you can ask UIKit to extend your app’s runtime.
You extend your app’s runtime by calling the beginBackgroundTask(withName:expirationHandler:) method. Calling this method gives you extra time to perform important tasks. (You can find out the maximum background time available using the backgroundTimeRemaining property.) When you finish your tasks, call the endBackgroundTask(_:) method right away to let the system know that you are done. If you do not end your tasks in a timely manner, the system terminates your app.
The key bits of that are:
"When your app moves to the background, the system calls your app delegate’s applicationDidEnterBackground(_:) method."
And "You extend your app’s runtime by calling the beginBackgroundTask(withName:expirationHandler:) method"
Note that you should really implement an app level "heartbeat" where the app sends periodic "I'm still here" messages to the server to keep the user logged in. Your server should log the user off if they miss more than one heartbeat message.
Related
I want to fetch location in background even if user forcefully quit the app. Currently my applicationDidEnterBackground method not called when user quit the app. It only works when user simply click on the home button.
Please refer to applicationWillTerminate
By Apple documentation it says:
This method lets your app know that it is about to be terminated and purged from memory entirely. You should use this method to perform any final clean-up tasks for your app, such as freeing shared resources, saving user data, and invalidating timers. Your implementation of this method has approximately five seconds to perform any tasks and return. If the method does not return before time expires, the system may kill the process altogether.
For apps that do not support background execution or are linked against iOS 3.x or earlier, this method is always called when the user quits the app. For apps that support background execution, this method is generally not called when the user quits the app because the app simply moves to the background in that case. However, this method may be called in situations where the app is running in the background (not suspended) and the system needs to terminate it for some reason.
After calling this method, the app also posts a
UIApplicationWillTerminate
notification to give interested objects a chance to respond to the transition.
If you want to have user's location when app is not in memory, short answer: Impossible.
I figured out about it is possible to download in background mode of application. I have implemented Background Fetching Mode in XCode and registered background task and its working fine.
Is it possible to resume downloading task after force closing my application by user? How?
No, you can't continue download when your app get terminated by user! Your app must require to remains in background state!!! Because if user force close app that means, he doesn't want to run it anymore. If your app is suspended by system then it can be wake up but not if it's terminated by user!
If an iOS app is terminated by the system and relaunched, the app can use the same identifier to create a new configuration object and session and retrieve the status of transfers that were in progress at the time of termination. This behavior applies only for normal termination of the app by the system. If the user terminates the app from the multitasking screen, the system cancels all of the session’s background transfers. In addition, the system does not automatically relaunch apps that were force quit by the user. The user must explicitly relaunch the app before transfers can begin again.
Update : (As asked in comment)
Refer the apple documentation, It states,
This method lets your app know that it is about to be terminated and purged from memory entirely. You should use this method to perform any final clean-up tasks for your app, such as freeing shared resources, saving user data, and invalidating timers. Your implementation of this method has approximately five seconds to perform any tasks and return. If the method does not return before time expires, the system may kill the process altogether.
For apps that do not support background execution or are linked
against iOS 3.x or earlier, this method is always called when the user
quits the app. For apps that support background execution, this method
is generally not called when the user quits the app because the app
simply moves to the background in that case. However, this method may
be called in situations where the app is running in the background
(not suspended) and the system needs to terminate it for some reason.
After calling this method, the app also posts a
UIApplicationWillTerminate notification to give interested objects a
chance to respond to the transition.
When any task completes, the NSURLSession object calls the delegate’s URLSession:task:didCompleteWithError: method with either an error object or nil (if the task completed successfully).
If the task failed, most apps should retry the request until either the user cancels the download or the server returns an error indicating that the request will never succeed. Your app should not retry immediately, however. Instead, it should use reachability APIs to determine whether the server is reachable, and should make a new request only when it receives a notification that reachability has changed.
If the download task can be resumed, the NSError object’s userInfo dictionary contains a value for the NSURLSessionDownloadTaskResumeData key. Your app should pass this value to call downloadTaskWithResumeData: or downloadTaskWithResumeData:completionHandler: to create a new download task that continues the existing download.
If the task cannot be resumed, your app should create a new download task and restart the transaction from the beginning.
checkout here: Life cycle of URL Session
Yes—if I understood your need right—Apple allows this with State Preservation and Restoration APIs:
Return your app to its previous state after it is terminated by the system.
Check Apple's article: Preserving Your App's UI Across Launches, for an overview of this framework.
Details about preservation process can be found in article: About the UI Preservation Process
Details about restoration process can be found here: About the UI Restoration Process
Raywenderlich have—a little outdated—tutorial implementation of this framework # State Restoration Tutorial: Getting Started
I am trying to understand Apple's doc for Background Execution:
Once configured, your NSURLSession object seamlessly hands off upload
and download tasks to the system at appropriate times. If tasks finish
while your app is still running (either in the foreground or the
background), the session object notifies its delegate in the usual
way. If tasks have not yet finished and the system terminates your
app, the system automatically continues managing the tasks in the
background. If the user terminates your app, the system cancels any
pending tasks.
When all of the tasks associated with a background session are
complete, the system relaunches a terminated app (assuming that the
sessionSendsLaunchEvents property was set to YES and that the user did
not force quit the app) and calls the app delegate’s
application:handleEventsForBackgroundURLSession:completionHandler:
method. (The system may also relaunch the app to handle authentication
challenges or other task-related events that require your app’s
attention.) In your implementation of that delegate method, use the
provided identifier to create a new NSURLSessionConfiguration and
NSURLSession object with the same configuration as before. The system
reconnects your new session object to the previous tasks and reports
their status to the session object’s delegate.
If I use NSURLSession, so when app goes background when uploading process is still on going, the process won't be killed or died as long as the application isn't terminated by user (I assume this is by killing my app from app list) ?
Read the text carefully. As all good documentation, it says very clearly what it means, and you just need to read it carefully.
You didn't read it carefully.
There are three cases: Your app is still running when a task finishes, your app has been shut down by the system when the last task finishes, or the user has closed down the app before the last task finishes. No, it doesn't say anywhere that the app is kept alive. And the documentation says clearly what happens in each case.
iOS kills apps that are in the background and makes it look to the user as if they are still running.
I'm little bit confused with background fetch. I read in Apple Developer documentation that fetch happens when OS decides that it should, user can't control background fetch, while on Apple Developer forum post by Apple employee says that if user kills app (double tap on home and button swipe up) background fetch wont happen, in that case user can control background fetch. So can someone please clarify to me if user kills the app with task manager will background fetch still continue in the background or it's killed at the same time as app.
Apple documentation:
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1
From the doc you link:
When a good opportunity arises, the system wakes or launches your app into the background and calls the app delegate’s application:performFetchWithCompletionHandler: method.
So, it seems that the system is able to launch in the background an app that is not running so it executes a background fetch. On the other hand, though, later in the document you can read:
In most cases, the system does not relaunch apps after they are force quit by the user. One exception is location apps, which in iOS 8 and later are relaunched after being force quit by the user. In other cases, though, the user must launch the app explicitly or reboot the device before the app can be launched automatically into the background by the system.
So, Apple's engineer is right: force quitting an app puts it into a sort of special case where background fetches are not allowed anymore.
If the user feels the need to allow background operations, he wouldn't kill the app. But when he kills it, it is only appropriate to disallow background fetch. User can only control if background fetch should happen or not by allowing it to stay in background/by killing the app. But once the app is in background, user cannot control "when" the background fetch happens. The OS determines it based on how free it is.
I think this quote (from the linked document) is the most important for the scenario you're describing:
Once configured, your NSURLSession object seamlessly hands off upload and download tasks to the system at appropriate times. If tasks finish while your app is still running (either in the foreground or the background), the session object notifies its delegate in the usual way. If tasks have not yet finished and the system terminates your app, the system automatically continues managing the tasks in the background. If the user terminates your app, the system cancels any pending tasks.
Our iOS app retrieves new app data every time it is freshly started i.e. not resumed from the background. App data is updated periodically every couple of months via web services so this is generally fine.
However, there may be edge cases where the user's iOS device - iPad, specifically - may keep the app suspended in the background for an extended period of time - potentially indefinitely.
Is it possible to mitigate this edge case by telling iOS "please release this app if it has been suspended for more than a few hours"?
The issue you describe is due to poor app design or a poor understanding of app architecture. If you need to refresh app data whenever the app becomes active you can simply call your update function off of the UIApplicationDelegate event (or register for a notification), specifically:
applicationDidBecomeActive:
Tells the delegate that the application has become active.
- (void)applicationDidBecomeActive:(UIApplication *)application Parameters
application
The singleton application instance.
Discussion
This method is called to let your application know that it moved from
the inactive to active state. This can occur because your application
was launched by the user or the system. Applications can also return
to the active state if the user chooses to ignore an interruption
(such as an incoming phone call or SMS message) that sent the
application temporarily to the inactive state.
You should use this method to restart any tasks that were paused (or
not yet started) while the application was inactive. For example, you
could use it to restart timers or throttle up OpenGL ES frame rates.
If your application was previously in the background, you could also
use it to refresh your application’s user interface.
After calling this method, the application also posts a
UIApplicationDidBecomeActiveNotification notification to give
interested objects a chance to respond to the transition. Availability
When the app is suspended it shouldn't be refreshing. Per Apple's documentation, unless your app has registered for one of the specific background processes, the app is essentially frozen until it resumes. There shouldn't be any network calls made.
However, if you DO want to kill the app once it's been suspended for too long, you could implement a hack that registers a background timer for 10 minutes, then after 10 minutes call some garbage code that you know will crash. Problem solved :)