How to create a background process on iOS (Swift)? - ios

I want to create a background task to execute some action with a timer, but don't kill that task when app is killed (for example I double click Home button and remove the app from that "list").

Timers don't run after an app is killed in iOS. Killing an app causes the OS to kill all of the apps timers, run loops, and background threads. All your app's executable code is likely deallocated from memory, so is not even around to run.
You could schedule a local (or remote) notification, but that won't execute any code in your app without user interaction. If there is an IFTTT app running on the device, and not killed, perhaps it could be scripted to launch your app periodically.

Related

Detecting iOS app background termination by system

What I'm trying to achieve is detecting when the system terminates an app while it is running in the background (not suspended). According to this article it can be done by process of elimination. One of the steps is deciding that user didn't force quit the app. I assume this is done by checking whether applicationWillTerminate was called. However, according to Apple's documentation this method can also be called by the system, so I'm not sure how it eliminates that option.
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.
Is it possible to detect background system termination, and if so, what am I missing here?
The App Programming Guide for iOS: The App Life Cycle says:
Suspended apps receive no notification when they are terminated; the system kills the process and reclaims the corresponding memory. If an app is currently running in the background and not suspended, the system calls the applicationWillTerminate: of its app delegate prior to termination. The system does not call this method when the device reboots.
In addition to the system terminating your app, the user can terminate your app explicitly using the multitasking UI. User-initiated termination has the same effect as terminating a suspended app. The app’s process is killed and no notification is sent to the app.
The above is consistent with empirical tests.
In that Reducing FOOMs in the Facebook iOS app article, they mention the force quit situation where the app did "receive a termination call the last time the app was open": That only applies if the app was actively running and the user force quit it. But if the user first returns to the home screen (or otherwise suspends the app) and then force terminates the app, you will not receive that termination.
Bottom line, if the app is suspended at the time it was terminated, I do not believe that you have any reliable way of knowing whether it was jettisoned due to memory pressure or because the user force quit. The force quit scenario contemplated in that FOOM/BOOM article clearly only applies if the app was running when it was force quit.

Is there a way to know when my app switches from Suspended to another state?

I'm having issues with my WKWebViews'cache being purged sometimes when a user hasn't been using my app for a while.
I guess, that's because iOS puts my app in Suspended and then a low-memory condition occurs so my app is purged.
I read Apple's documentation about The App Life Cycle - Execution States for Apps
Especially the part describing the Suspended state :
Suspended - The app is in the background but is not executing code. The system
moves apps to this state automatically and does not notify them before
doing so. While suspended, an app remains in memory but does not
execute any code. When a low-memory condition occurs, the system may
purge suspended apps without notice to make more space for the
foreground app.
Two questions here :
1) What does "purge" mean exactly ? The app is killed ? Or does it still appear on the app selector ( when double-tapping the home button )
2) Here we can see that there is no way to know when an app is going to be suspended. All right. But if a user comes back to the app, is there a way to know, then, that the app has been suspended ? I can't find any UIAppDelegate's method to do so, but there might be another solution ?
Purge - The purge command forces disk and memory caches to be emptied,
offering a ‘cold disk buffer cache’ which is similar to the state of
the operating system after a reboot.
Referenced from here
As per the documentation
applicationDidEnterBackground:—Lets you know that your app is now
running in the background and may be suspended at any time.
This is the only method which will let you know that method may will enter in Suspended State
also
application:didFinishLaunchingWithOptions: will let you now that
your app's launch process is almost done and the app is almost ready
to run.
The app is in the background but is not executing code
I think it's explained good by Apple, the app is still in memory but no background threads are executed since foreground app requires more resources. Maybe when memory is restored, your app can execute background code again if has not been killed by OS.
When low-memory condition occurs, you're app could be killed (purge).
Is there a way to know, then, that the app has been suspended?
When app is killed from OS, next launch is equal to a complete new restart of app. For this AppDelegate doesn't provide a method to achieve this. You could set a flag in UserDefaults when app goes in background and then make some logic on that flag.

How to avoid iOS app being terminated by system too often when in background

I'm building an iOS app for iOS 8 & 9 and I am facing the problem that when the app goes to background the system is terminating it after just 2 or 3 minutes.
My testing is easy:
I kill all running apps from my iPhone.
I restart my iPhone (to ensure no other apps are taking memory).
I launch my app.
I do nothing inside my app.
I press the "Home" button, moving my app to background.
I wait doing nothing else for 2 or 3 minutes.
I open my app again and surprise, the system has terminated it and now it is restarting as a new launch.
Some comments:
The app does not use CoreLocation in background neither any other service.
I've profiled the app, trying to understand if it is consuming too much memory. When moving to background, it consumes around 25Mb of RAM memory. I'm attaching a screenshot below.
This behavior has been tested on iPhone 5, 5s, 6, 6+.
In iPhone 6s and 6s+ seems to take a bit more time to happen, but still happens.
My question is: Do you know why would this be happening? anything I might not be considering or just forgetting?
I don't want to force my app to run in background by using CoreLocation or something similar. And I'm ok if the system kills my app eventually. What I don't want is that everytime I move my app to background the system terminates it.
Any hint or help will be appreciated.
Thanks,
All applications are automatically killed by the system
According the Apple documentation:
App Termination
Apps must be prepared for termination to happen at any time and should not >wait to save user data or perform other critical tasks. System-initiated >termination is a normal part of an app’s life cycle. The system usually >terminates apps so that it can reclaim memory and make room for other apps >being launched by the user, but the system may also terminate apps that >are misbehaving or not responding to events in a timely manner.
Suspended apps receive no notification when they are terminated; the >system kills the process and reclaims the corresponding memory. If an app >is currently running in the background and not suspended, the system calls >the applicationWillTerminate: of its app delegate prior to termination. >The system does not call this method when the device reboots.
In addition to the system terminating your app, the user can terminate >your app explicitly using the multitasking UI. User-initiated termination >has the same effect as terminating a suspended app. The app’s process is >killed and no notification is sent to the app.
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html#//apple_ref/doc/uid/TP40007072-CH2-SW1
You can track position but you will certainly see a blue status bar to indicate that an application use GPS tracking.
Maybe you can try to "wake up" your app in background with silent notification...
If it is not necessary to keep your app alive, trust the system...
Some error in inside your code. Please select debug Navigator before run your app... Now you can able to find your error..
Or too much memory also it will terminated..
Apps which are running in the background drain battery life faster, It gives you a bad perception of the device, instead of the app, because the average consumer has no idea that it's an app draining battery.
Thus iOS won't allow your app to run in the background, more than a few seconds. But there are some exception, an app can request extension to this by declaring that its starting a Background Task.
for more info you can check below links:
http://blog.dkaminsky.info/2013/01/27/keep-your-ios-app-running-in-background-forever/
http://www.speirs.org/blog/2012/1/2/misconceptions-about-ios-multitasking.html

How to test Background App Launch in case of NSURLSession(Background Session) event?

How can one test the scenario of Application Launch in background for handling Background NSURLSession's event?
Flow:
Application starts a upload/download task using Background URL
session.
User hits home button. App is in suspended or in background
state.
OS decides to Exit the application. I know, one can exit the app by double-tapping home button and swipe-up the particular app. But in that case OS will never re-launch the app in background for event handling.
Upload/download task needs some event handling. OS re-lauches App in background.
So the question is how do I make OS exit the app like it may normally do after some-time. The purpose is to test the code for this scenario. I tried using UIApplicationExitsOnSuspend but it does not work since then App can not be launched in Background.
It's not a perfect solution, but I was able to manually test the launch of an app due to a Background URLSession on a physical device as follows:
Connect device for debugging via USB
Disable Internet connectivity on device (i.e. disable WiFi/Cellular)
Start the app via Xcode
Issue a request using background URLSession. The request shouldn't fail, it will just be waiting around for an Internet connection until it times out, so use a reasonably long timeout to make testing easier.
Kill the app via Xcode (press stop button)
View the device logs via Windows > Devices and Simulators
Enable Internet connectivity on the device again without starting the app
The requests from the background URLSession should then complete and in the device logs (from step 6.) you should see any NSLog statements issued as a result of the app being launched via the application(_:handleEventsForBackgroundURLSession:completionHandler:) app delegate method.
They key point is that killing the app via Xcode, as opposed to killing it using device itself, does not prevent the app from being relaunched for background event handling.
A possible alternative to killing the app manually via Xcode might be to intentionally crash the app in code - this might be more suitable for automated testing.
You could write an app that has a button that allocates and intentionally leaks chunks of memory. If you get this thing to allocate enough RAM, the OS will start killing other apps to get their RAM back.
Hopefully this would exhibit the behavior you need.

iOS: Does force quitting the app disables background upload using NSURLSession?

The question is around NSURLSession and NSURLSessionUploadTask.
I'm uploading large files to server and noticed that when I force quit the app the whole background upload just stops. However, when upload starts while app is running through the Xcode/debugger, then my upload completes just fine even when I stop the app running via Xcode 'stop' button. I suspect that force quitting the app using Xcode simulates an iOS system command and not a user action.
So my question is whether it's true that iOS would immediately cancel NSURLSessionUploadTask when user force quit the app?? For some reason I would at least expect an error callback to the app, however nothing happens.
I can confirm now after a bunch of testing that background task will run ok if the app is just put into background. However, if user force quit the app manually, then iOS cancels all scheduled background tasks. So next time the app is launched I'm getting all the callbacks to the delegate with the error code of a canceled task.
Hope it helps someone looking into the same thing.
From Apple's docs about background execution:
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.

Resources