iOS Reachability when app is in Background - ios

My application requires exact information on whether or not user is connected to Wifi network and not on internet connectivity so do not comment on the use case please. The task is: user needs to verify that their Wifi is connected but if they dont have any Wifi network available to connect to, they can do it later. For this I need my app to notify the user when he later connects to a Wifi network that now you can continue with the test.
Can I accomplish this using Reachability in background fetch request? Are there any limitations to tasks that app can perform in Background fetching?

This is not solvable in the general case. You cannot run arbitrary code in the background for an indefinite period of time (unless you already are an allowed background task for other reasons, such as location services or VoIP, but these still have restrictions). And you cannot request to be launched when reachability changes.
You can, however, configure an NSURLRequest to not use cellular access. That's not exactly the same as "wireless" but it's close and may be what you actually mean (you're not clear on why "wireless" is the criteria). You can then use NSURLSessionUploadTask or NSURLSessionDownloadTask to ask the OS to perform the action when possible (without waking you up or involving you in any way when you're in the background). If that request were to your server, you could then use a push notification to alert the user and achieve the experience you're describing.

Related

Network options when app is in not running or terminated state

We are building an iOS iPhone app that needs to check-in with a server on a 12 hour basis. This is needed to let the server know that the app is still using it's service on the server. To our understanding this is possible when the app is in background state (not showing on the foreground) via backgound fetch or remote notifications.
But this is not possbile when the app is not running or terminated, when the app is in these states then there is no way to initiate communication with a server. Is this statement corret? Is it possible initiate the communication after a device bootup, is it then possible to send a small keep alive message to te sever?
The background fetch and responding to remote notifcations is not possible in the not running and termenating states(?), so we cannot use these mecahnisms for this purpose. If that is the case are there any other solutions that we can try? Or is it just not possible?
We looked at many sources on the internet but some say that it is possible and others say it is not.
You might want to take a look at the Silent Push Notifications. Here is the thing, if the app is in background mode or suspended state, you will be fine. If the app was killed by the user, you have a problem.
You can always send a silent push notification, and wait for a service call made from the device to your service. If there is a response, it means the app was in background or suspended, and then you can go ahead and do whatever you need to do. If no request is made, it means that app was killed. Then you might want a sent a non silent push letting the user of that device know that he needs to launch the app or something like that. I don't know how you are going to work around it, but that could be a possibility.
I would tell you to take a look at NSURLSession and Background NSURLSessionConfiguration as well, but you will run into the same issue. If the user manually terminates the app, you need to find a work around to set up that connection to the server, and that will imply the user to somehow launch your application.

Why don't downloads switch back to wifi after been on a cellular network?

I have encountered a rather strange behavior when trying to implement download functionality on iOS. The download implementation works fine in that it finishes successfully, can run in the background, and file is stored on device. However during a download, I can turn of wifi to let the task switch to and continue on cellular network (or just start the download using cellular). This behaves as aspected. But when I enable wifi again, the download never seem to switch back to using wifi. The device is connected, and the wifi-connection-bars displays at the statusbar. Using rechability functions to check what connection that is available will even return Wifi, but the download seems to be stuck at using cellular.
The way I am detecting this is looking at the Usage stats in the system settings. The cellular data usage will rise in sync with the pending download, and continue to rise until the download is finished (even if wifi is turned on again).
I have tested with both Alamofire and by using NSURLSession and NSURLSessionDownloadTask directly, and they both behaves similarly. I have also seen this behavior in two completely seperate projects, on multiple devices, in iOS 8.4 and 9.1, when the apps are in the foreground or the background, and even AppStore behaves like this when downloading apps!
Has somebody else experienced this?
And if so, did you find any way to gracefully switch tasks back to wifi?
Thanks in advance.
This is normal behavior. Adding a new network interface (e.g. turning Wi-Fi on) doesn't stop existing TCP connections. They will continue until the original network interface goes away.
If you want to pause the request and reconnect when Wi-Fi becomes available, you'll need to call cancelByProducingResumeData: on the task, then create a new request with that resume data to restart the request from where it left off. That new request will go over the currently active network interface, which would typically be the Wi-Fi interface if Wi-Fi is up and running.
Before you stop the existing request, though, I would suggest trying a probe request for something like Google's generate 204 or one of Apple's captive portal detection URLs, to ensure that Wi-Fi really is working.

NSURLSession background download over cellular possible in iOS 8?

I need to make small downloads initiated when my app is in the background and woken up by Significant Location Changes. BUT Apples documentation of NSURLSessionConfiguration here:
https://developer.apple.com/library/IOs/documentation/Foundation/Reference/NSURLSessionConfiguration_class/index.html#//apple_ref/occ/instp/NSURLSessionConfiguration/discretionary
says the following for the discretionary property:
When transferring large amounts of data, you are encouraged to set the
value of this property to YES. Doing so lets the system schedule those
transfers at times that are more optimal for the device. For example,
the system might delay transferring large files until the device is
plugged in and connected to the network via Wi-Fi. The default value
of this property is NO.
The session object applies the value of this property only to
transfers that your app starts while it is in the foreground. For
transfers started while your app is in the background, the system
always starts transfers at its discretion—in other words, the system
assumes this property is YES and ignores any value you specified.
This seems to imply that if a download is started in the background the OS always has discretion as to whether and when to proceed with the download. It seems that the OS is always waiting for a wifi connection before completing these tasks. My experience supports this conjecture. I find that I can send several notifications for downloads while device is on cellular. They remain stuck. When I switch the device to wifi they all go through.
WTF? Why Apple prohibits configuring this behaviour, especially since they HAVE the neccessary properties on the NSURLSessionConfiguration object (discretionary, allowsCellularAccess). Of course the user is not always in WiFi when download tasks are started. I need to do this in response of app wake-ups by significant location changes. I schedule download tasks on a background session and never receive delegate callbacks on cellular network until I switch to WiFi. So does that mean I cannot finish these tasks unil WiFi is available again or I bring the app back to foreground?
Has anybody of you a workaround for this?
I already thought of the following:
Starting a long running background task (old style) after a location update and download my stuff there by using a defaultSessionConfiguration. Any experiences if that can work? If this doesn't I will use NSURLConnection I think (even more old style).

Proper way of checking for Reachability and App Store submission tips

I have read in the App Store Submission Tips that
If your application provides functionality that requires access to a network, it's very important that your code include a customer alert or notification when the network is not available.
In fact, there are two entries in that submission tips list concerning Reachability (Don't Forget to Include Network Error Alerts in Your Code and Be Sure to Provide Network Error Messages). But I don´t know how an app is expected to manage Reachability actually:
1) Should you listen for network reachability status changes, and notify the user every time the network is not available? Or should you check for the reachability of the network when you are about to perform a network operation, and then notify if needed? Or both?
2) Is it required to check for the reachability of the certain remote hosts you need to call in your network operations, or checking for network availability (either WiFi or WWAN) will be enough?
I'd appreciate some guidance from someone who had already successfully submitted an app to the App Store.
Thanks in advance
1) If your app only needs to access the network when the user specifically chooses to do something, then checking at that time is fine. Depending on your app, you might want to listen for changes in reachability and update your UI based on the current status (such as disable a button if there is no network connection). Don't pop alerts every time the reachability status changes. That would be annoying.
2) Depends on your needs. If you have something that always connects to a specific host then checking that host would be good. If the access can be to anything on the Internet then simply check for Internet access.
All of this can be done with the Reachability class from the "Reachability" sample app.

Detecting Whether an iPhone has roamed from wifi to 3G or vice versa

G'day Guys,
I've been using the reachability API with reachability status callbacks to determine whether an application is connected over 3G or wifi. It's an application that acts as a voice extension for an existing piece of hardware and as such we're using the VoIP APIs to run in the background and accept calls etc.
Is there a definitive way other than using reachability status callbacks to determine whether you can access a particular IP endpoint or not? I could use an ASIHTTPRequest and then check if it timed out but that may cause potential problems for me in the long run.
I'm not looking for a programmatical answer but more any insights other developers would have on how to manage a roaming between the two in the background if you have a persistent connection. Basically if the device roams over to 3G I need to destroy the session on the device and if it roams back over to Wifi I need to recreate the session.
Any feedback or advice would be welcome.
The Reachability APIs will provide the connection change notifications to your app so that you can know when the connectivity changed from WWAN to wifi. It will not tell you if you've changed from Edge to 3G or LTE unfortunately. The Reachability API also has methods to test reachability to a specific host. So, in your app you can listen for the notifications that the connection method has changed, then when it does change test reachability to your target host and at that time make the decision whether to rebuild the session or leave it intact.

Resources