Does the iOS platform provide background sync? - ios

If the user performs an action in an iOS app while offline (e.g. airplane mode), can the app complete the action (by sending data to its server) once the user is online, even if the user completely closed the app before going online?
I’m asking because Twitter and Facebook do not have this functionality. (If I post something while offline, then close the app and go online, the post will not be submitted until I start the app again.)

No. If the user kills your app, it's gone. It can no longer execute any of your applications code. The best you can do is research background tasks and you then have ~10 minutes to execute your actions before it's automatically terminated (if the user doesn't do it before the OS).
You can store the actions in a Database (Core Data, Realm) or even in NSUserDefaults. When the app comes online, you can periodically attempt to parse those actions and send the network requests with exponential back-off. I imagine this is the process Facebook and Twitter use.

I disagree with #JoeyClover's answer.
If what you want to do is an HTTP POST, you should be able to set up an NSURLSession for background processing. The system should then take over submitting your post even if the app is not running. See Xcode's docs on NSURLSession for more information. (You can do the same thing for downloads with an HTTP GET, but that's not what you're asking about.)
The exception to this is if the user actually terminates your app by swiping up on it in the task list. In that case the system kills your background upload/download tasks. The info on that is in the section on NSURLSessionConfiguration. To quote Apple's docs:
Use this method to initialize a configuration object suitable for
transferring data files while the app runs in the background. A
session configured with this object hands control of the transfers
over to the system, which handles the transfers in a separate process.
In iOS, this configuration makes it possible for transfers to continue
even when the app itself is suspended or terminated.
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.
(I bolded the key bit.)

Related

Will download resume after closing my app in Background Mode

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

Handling server being aware if iPhone app is running (heartbeat)

I am not sure how to best implement keeping our server informed that our iPhone application is currently running (even when in the background). There are a few different options but there is some concern as to what is allowed by the Apple approval process as well as what is the most reliable. The application does have the ability to play music in the background, if that factors into what is approved by Apple.
The first option, is to continually send some sort of heartbeat to the server at a set interval through a simple GET/POST; however, the concern is whether or not this is allowed as a background task. In a very roundabout way it can be argued that it is necessary for the playback but I'm not so sure whether or not that is acceptable. If the server does not hear from them in a set amount of time it will assume the app is no longer running.
The second option involves using a presence channel socket connection and have the server just handle when users enter and leave that channel. With this option the main concern is how reliable is a socket connection like this while an app is in the background. Similarly, whether or not this is allowed by Apple. In this case when the app dies, connection closes and server knows app is not running.
Third option can be used in tandem with either of the other options but to use some sort of APNS push to query the phone as to whether or not it has died and have it respond with some data to let us know; however, this seems somewhat counterintuitive as the push itself wakes the app up.
Any other suggestions or input are also welcome.
Not sure if this should be a comment or answer, but let me put my 2 cents here.
Firstly, Can you please elaborate your needs further, because in case you are playing an Audio in background with AVPlayer/AVPlayerItem you would hand over your content URL to iOS and it will make the calls as and when necessary to keep the playback running, you dont need to know about apps' state.
Let me assume, for whatever reasons you want to achieve what the question asks:
There are 3 states your app can be in when it is "Not Running"
i. Suspended State: your app is not killed but its not receiving any CPU time to execute your code.
ii. Killed by OS: Your app can be terminated by iOS to free up the memory or any other resources.
iii. Force Killed by User: If user swipes up your app from app switcher it gets force killed.
Now when your app is Not Running, you CAN NOT query it, but you can move it to Running State. You can achieve this transition by using following methods (Not exhaustive list, but mentions common ways)
i. Background Fetch : You can configure your app to be invoked periodically, so that it can synchronise with the server and updates its state.
ii. Push Notifications (APNS) : You can ping the app from server so that iOS invokes it for some short period of time (few seconds) to update its state.
iii. VOIP Pushes: If your App is VOIP app you can use PushKit to send Silent Pushes which will launch even the Force-Killed Apps, the above two methods does not transition the app to Running state if it was force killed by user
The above point can be helpful in devising overall strategy but does not answer the question, "How to keep syncing the RUNNING state"
i. When your app is Running(Forground/Background), you can do almost anything that is publicly documented, you can keep calling a URL every minute or every 5 seconds, you need to worry about UX on the device rather than approval process, (People will delete app if they see your app in top battery drainers in the settings section)
ii. For making an HTTP call while your app is in background, you can look at Background URL Session, which off loads the HTTP calls to another process so that the call completes even if app gets killed.
iii. For the socket based approach please refer this technical note. The main issue is that you do not/can not know when your app moves from Running to Not Running State.
iv. As you mentioned that your app uses background audio, it will be always be in Running state if the user plays an audio and puts app in background, in such case you can use Periodic Observer to do some Heartbeat call periodically when the content is being played out.

How to send content to server in background ? ios

First of all i need to describe what i am going to do: when user launch my application the app start collecting statistics about the user activities and behavior, once the the user close the app (app enter background) the application upload all statistics to server.
the problem if the user presses home button twice and removes application from multitasking screen. then the application may not succeed to send statistics to server. because it will be terminated.
my solutions:
enable Background fetch , in background modes. but I don't think that will help because according to apple: the system does not relaunch apps after they are force quit by the user
using Executing Finite-Length Tasks , i tried it , it won't send the data if user remove the app from multitasking screen.
using NSURLSession to Downloading Content in the Background, but according to apple If the user terminates your app, the system cancels any pending tasks.
so all above solutions will not work if user terminate the application, any solution ?
I noticed that if i terminate the appstore app (remove it from multitasking screen ) while there is an application being downloaded , the application will continue downloading normally. is this just for appstore app ?
If the user terminates an app, the app terminates. There is nothing you can do about this. iOS devices are meant to be controllable by the user.
Depending on what you are trying to achieve, you might add all the statistics to a queue on disk, and empty that queue only after the app has successfully uploaded the data to the server.
If the user doesn't force-quit, this will work at once, in just the way you want.
If the user does force-quit, the data will not be uploaded and the queue will still be present on disk. When the app is started, it can check the queue and upload it immediately.
You ought to be doing something like this in any case, to deal with cases like the user going underground for an hour, or taking a long-distance flight.
I suspect that the App Store app does not install apps, but tells a system process to install them.

iOS background fetch

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.

guaranteed delivery for uploads after network reconnect, even if my app is not running

I'm spec-ing an iOS app (which will be built outside of our company) which will upload a user's data entry to a server. If the device is not connected to the Internet, we'd like to save data on the device and upload it when the network is re-connected. (The app will primarily run on iPod Touch devices that will be disconnected most of the time).
If the user unlocks the device and re-opens our app after the network is reconnected, then uploading to the server should be easy because the app is running.
But what if the app is not running, where "not running" can mean one or more of:
device was power cycled
user has locked the device and it's sitting in his pocket
app crashed
user exited the app
user started using other apps so our app isn't running in the foreground anymore
are there other cases?
In the cases above, is there a way (ideally a battery-efficient way) to ensure that local data is uploaded soon after Internet connectivity is restored? Is the answer different depending on which of the cases above caused the app not to be running?
And is there a minimum iOS version the device will need in order to enable some (or all) of the above not-running cases to still upload when the app is not running?
My apologies if these are obvious newbie questions-- I'm not an iOS expert.
There is an interesting technique that is used by among others Instapaper and News.me(the pioneers of this technique) where you use region monitoring to initiate background downloads or uploads. Marco (Instapaper) blogged and talked (in episode 80 of the Build and Analyze podcast) about his communication with Apple so it should be a allowed in the App Store.
In brief the technique is that you set up certain regions (geofences) like "home" or "work" and respond to the locationManager:didEnterRegion: (and similar) callback(s). Your app will wake up from the background once you enter the pre-specified region and you can check to see if there is any data to upload.
This technique won't guarantee that the data is uploaded when the network reconnects but it will allow your app to automatically upload the information when the iPod Touch users gets home to their WiFi network.
That should most likely be at least once a day which may or may not be frequent enough for you. You could add a timestamp to when the initial upload was attempted and send that along the upload once it succeeds to get the correct order of events (data entries) on your server.
There is no way to ensure this. If your application is "not running" (by the definition described in your question), it will not be capable of responding to a change in the device's network status. It should be setup to resume upload operations the next time the application runs again.
EDIT:
Some of the cases you've described may indeed provide different opportunities for your application. Specifically, if the user "exits" the app by pressing the home button or launches another app in the foreground, your application may continue to run the in the background and could potentially respond to a change in network reachability.
The nature of what may be done in the background and for how-long is well documented, and supported by any version of iOS that supports multi-tasking. I recommend you review the documentation pertaining to App States and Background Services.
device was power cycled --> really NO WAY of resuming, unless you open the App!!!
user has locked the device and it's sitting in his pocket --> apps applicationStatus is UIApplicationStateInactive but it is running in the background. You still are able to react to notifications and i.e. accelerometer events. Try the Reachability Class and Log the changes!
app crashed --> NO WAY, unless opening the App
user exited the app --> App is sitting in the background. There you have a maximum of 10 Minutes Restriction of fully using your App (like the App "Pastebot" does)
user started using other apps so our app isn't running in the
foreground anymore --> Same as user exited the app
On multitasking Apple says the following:
Real multitasking only for certain kinds of usage, as there is Audio Background playing, VOIP (like Skype), navigation applications
All the other apps can request a specific amount of time after the app is closed/in the background, to finish certain tasks (as sending an email, sms or uploading/downloading important data)
Important Quote from dev docs:
Your app delegate’s applicationDidEnterBackground: method has approximately 5 seconds to finish any tasks and return. In practice, this method should return as quickly as possible. If the method does not return before time runs out, your app is killed and purged from memory. If you still need more time to perform tasks, call the beginBackgroundTaskWithExpirationHandler: method to request background execution time and then start any long-running tasks in a secondary thread. Regardless of whether you start any background tasks, the applicationDidEnterBackground: method must still exit within 5 seconds.
If you're building a restful API then I would recommend using RestKit, it has a request queue that checks the network status on the device and starts uploading once network access has been assured. You can read more about this here: http://mobile.tutsplus.com/tutorials/iphone/advanced-restkit-development_iphone-sdk/. Read the sections about Request Queue and background download/upload. It should be noted that RestKit is a big library which has it's advantages and disadvantages. I'm not completely sure how this que works with the app lifecycle, if it saves the request que even if the app is terminated. You would have to investigate that. RestKit does support background uploading/downloading, but as already noted, I think it's impossible to do any uploading if the app is terminated and not in background state.
I wouldn't recommend using RestKit if the API isn't Rest though.
You can download and experiment with RestKit here: https://github.com/RestKit/RestKit.

Resources