I am building an app targeting iOS 8.0 that needs to download files that are up to 250Mb. I had a version of the download code roughly working using Alamofire
but I recently replaced that with a pure NSURLSession
implementation. This new implementation is working as expected in the simulator and on my iPhone 5S running iOS 9.2 (13C75). It works on my phone whether I install through XCode
and a physical connection or through TestFlight
. I have deleted the app, restarted the phone, and reinstalled and it always completes downloads correctly. One of my colleagues pulled the code and was able to successfully simulate it from XCode
.
However, downloads fail on all of my collaborators' devices. They are installing the app through TestFlight
and are set up as internal testers. One collaborator also has a iPhone 5S running iOS 9.2 (13C75). The Alamofire
-based implementation worked as intended when deployed through TestFlight
to those same devices and very little other code has changed.
I have added some remote logging and I can see that on the failing devices, downloads are correctly triggered and the download tasks I create each have a taskIdentifier
which I can log. However, none of the NSURLSessionDelegate
or NSURLSessionDownloadDelegate
methods are called.
What suggestions do you have for troubleshooting?
Is it possible that this could be related to a TestFlight
problem? My current next step is to try an alternative to TestFlight
. Ultimately, I would like to be able to deploy betas through TestFlight
if possible.
I'm using Swift 2.1.1
in XCode 7.2 (7C68)
.
The problem turned out to be that I had set the NSURLSessionConfiguration
discretionary
property to true. The docs state the following which sounded good to me:
When transferring large amounts of data, you are encouraged to set the value of this property to true.
But I failed to appreciate the consequences of the rest of the text:
For example, the system might delay transferring large files until the device is plugged in and connected to the network via Wi-Fi.
The reason that installations through XCode
were working was presumably that the phone was either being charged because it was connected to my computer when I started a download or had just been charged.
I initially suspected that the problem came from either TestFlight
or something about the state of the phone. Remote logging with Sentry (which I already use for the backend) was very helpful for getting some insights into what was different when my collaborators ran the app. I eventually added in implementations for all the NSURLSessionDownloadDelegate
methods to log which ones were called. This led me to see that didReceiveChallenge
was the only delegate method being called and I then spent some time thinking that it could be an auth-related problem and troubleshooting in that general area.
Finally, I started noticing that my own install would fail sometimes and one collaborator had a successful download. That made me start thinking about the kind of phone state that could prevent a download. I went back to the NSURLSession
configuration that I had and that's when I read about the discretionary
property.
In retrospect, carefully checking the configuration would have been a good step to do earlier. Another good thing to do would have been to log the state
property of the download tasks that were created.