25 Replies
      Latest reply on Jul 30, 2019 2:58 AM by remy.san
      adamzucchi Level 1 Level 1 (0 points)

        I've recently been integrating Background Transfer Service into an application so that the user is able to download files in the background.

         

        I did most of my building/testing on an old iPhone 6 device that was running iOS 9.3.5 (I try to keep my previous device back a version of iOS).  Background Transfer Service works great on this device.  I am able to put 100+ download tasks into the queue and they all finish and report progress as expected after sending the application into the background and then re-opening the application.

         

        This also appears to work great on a new 5th generation iPad running iOS 10.3.

         

        Where things get weird is on my iPhone 7 Plus which is running iOS 10.3.1.  The downloads kick off fine, progress is reported as expected in the didWriteData method, however if I background the application and wait ~10 seconds and re-open the application the progress never catches back up to what progress would have been done in the background and the progress never increments at all (it stays where it was when it was backgrounded).  The didFinishDownloading method does end up getting called however it appears to wait until the very end of all the download tasks completions for that method to fire for all of the remaining tasks.  So the didWriteData, didFinishDownloading, didCompleteWithError, etc. all happen right at the end in one burst. 

         

        I have however had a few instances where my iPhone 7 Plus device running iOS 10.3.1 did show progress after bringing the app back into the foreground however those instances I could could on one hand.  More often than not (9 times out of 10) the progress is never reported on this device after re-opening the application.

         

        I am at a bit of a loss and am wondering if there is a known bug we should be looking out for, and if so when we could expect a fix?  Or if there are currently any known work arounds.  From my testing/debugging I cannot get progress to work in my application on the iPhone 7 Plus running 10.3.1.  I also had a co-worker test this as well and they also experienced this.

         

        In fact they went a step further and opened the Netflix application on their 10.3.1 iPhone 7 Plus device and began downloading a movie.  Progress incremented as expected, they then backgrounded the application and waited ~20 seconds and re-opened the application, only to find the progress get stuck where it was when the app was initially backgrounded and it never moves.  After a given amount of time of the progress not moving the download does eventually finish (the progress indicator disappears) and the Netflix movie is downloaded and able to be played.  This is the same behavior I see above in my application.

         

        Any help with this would be greatly appreciated.

         

        Thanks in advance!

         

        Adam

        • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
          eskimo Apple Staff Apple Staff (11,625 points)

          I’m in two minds about this.  On the one hand my suspicion is that, if this problem were widespread, I would have seen lots of reports from other developers about it.  On the other hand, your investigation so far seems to strongly indicate that this is a bug in NSURLSession.

          Three points:

          • I presume that you’re testing this by running your app from the Home screen rather than from Xcode.  See my Testing Background Session Code pinned post for information on why this is important, and for other testing tips.

          • If this is a problem it’s caused by NSURLSession not correctly reconnecting to the session when you come back from being suspended in the background.  One interesting test would be to terminate your app to see if things work in that case.

            IMPORTANT Do not test this by force quitting your app.  That will cancel all of your requests.

            You can test this by adding a ‘Quit’ button to your app that terminates the app by calling exit.  This is not acceptable in a production app (see QA1561) but it’s handy for testing.

          • Have you tried reproducing this with a small test app?  The obvious candidate here is the Simple Background Transfer sample code.  If the problem occurs in that sample (even if it requires a few tweaks to get it to reproduce), that’s definitely bugworthy.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
              adamzucchi Level 1 Level 1 (0 points)

              Thank you for the reply.

               

              I can confirm that I was running the applications from the homescreen and not from the Xcode.

               

              I downloaded the Simple Background Trasnfer project you mentioned above and tested a download on the 3 previously mentioned devices and got the same results.

               

              I did go ahead and file a bug with Apple, here is the Problem ID issue #: 32247561

               

              I attached a screen recording of the issue in the bug and also provided a URL of screen recording in the additional notes of the bug in case you are interested in seeing my results.

               

              Thanks again for the help, we'll see where this goes!

                • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                  eskimo Apple Staff Apple Staff (11,625 points)

                  I did go ahead and file a bug with Apple, here is the Problem ID issue #: 32247561

                  Thanks.

                  Did you try my exit test?

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                    • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                      adamzucchi Level 1 Level 1 (0 points)

                      Not yet - I plan to test that over the weekend.  I'll let you know what I find.

                      • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                        ramyad Level 1 Level 1 (0 points)

                        Hi Eskimo

                         

                        I'm seeing the same issue with iOS 11. NSURLSessionDownload delegate methods are not invoked when app resumes from background. Could you please let me know, the status of this issue. If not are there any workarounds?

                          • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                            eskimo Apple Staff Apple Staff (11,625 points)

                            I don’t know of any current problems with the OS that would cause behaviour like that described above.  Most issues like this are caused by folks misunderstanding how background sessions are supposed to work.  On the main Core OS > Networking page you’ll find a bunch of pinned posts that explain some of the most common gotchas.

                            Share and Enjoy

                            Quinn “The Eskimo!”
                            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                            let myEmail = "eskimo" + "1" + "@apple.com"

                              • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                adamzucchi Level 1 Level 1 (0 points)

                                I'm not sure how I misunderstood how background sessions work? 

                                 

                                I posted the example of this happening to me using Apple's source code back in May and filed a bug report but have gotten zero response from Apple.

                                 

                                http://adamzucchi.com/stage/apple/backgroundtransferservice/index.html

                                 

                                https://bugreport.apple.com/web/?problemID=32247561

                                  • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                    eskimo Apple Staff Apple Staff (11,625 points)

                                    I wrote:

                                    Most issues like this are caused by folks misunderstanding how background sessions are supposed to work.

                                    adamzucchi wrote:

                                    I'm not sure how I misunderstood how background sessions work?

                                    That post wasn’t in response to anything you wrote, but in response to ramyad’s post from the 2 Nov.

                                    With regards your issue, I haven’t had a chance to look into this in depth but your analysis so far is strong evidence that this is a bug in the OS.

                                    As to workarounds, I’m curious if you can see progress being made by polling the various NSURLSessionTask properties (like countOfBytesReceived or countOfBytesSent), or via KVO-ing properties on the object returned by progress.

                                    Share and Enjoy

                                    Quinn “The Eskimo!”
                                    Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                    let myEmail = "eskimo" + "1" + "@apple.com"

                                      • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                        Universalis Level 1 Level 1 (10 points)

                                        I apologize for digging out an old thread for a problem which may well have been resolved since then, but just to add, for Quinn's benefit:

                                         

                                        1. I am seeing it too, on iOS 10.3.3. That is: Home button halts the didWriteData method calls (after a short time which I'll call T), tapping on the app icon does not always resume them. (My "not always" is "about half the time").

                                        2. Yes, to cause the problem it is necessary to wait a few seconds after pressing Home, before tapping the app icon.

                                        3. As has been reported, the didFInishDownloading method is called even if the didWriteData calls aren't coming through.

                                         

                                        4. Quinn, I have tried the KVO of countOfBytesReceived, as you suggested. Its behaviour is identical to that of didWriteData. If a KVO is triggered, so is the method call. If no method call appears, no KVO appears.

                                         

                                         

                                        5. NEW: If, after pressing Home, waiting, and tapping the app icon, the didWriteData calls do not happen, then sometimes pressing the Home button will cause a short burst of didWriteData calls. The time that burst lasts is, to my eyes, about the same as the time T which I mentioned in point 1. As if some sort of "send / don't send" toggle missed a beat and thus goes from NO to YES on pressing Home, only to get shut down shortly afterwards because the app is suspended.

                                         

                                        This is not a hugely urgent issue for us, in that users have not reported it. Moreover, the quiescence of this thread suggests that the problem, whatever it was, was corrected in iOS 11 – otherwise I would have expected to see more reports. I have not, myself, attempted to reproduce the problem in iOS 11.

                                         

                                        Nevertheless, if anybody sees any sign that the problem does occur in iOS 11 then I will go ahead, attempt to reproduce it, and report any results. It would be good to get this sorted out (if it still needs it).

                                        • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                          giantguppy Level 1 Level 1 (0 points)

                                          I tried polling countOfBytesReceived and it does not update.  (this is on iOS 12.0)

                            • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                              giantguppy Level 1 Level 1 (0 points)

                              I have the same issue on iOS 12.0.  Is there any solution in sight???

                              • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                TimAtBcov Level 1 Level 1 (0 points)

                                Me too - 100% reproducable when running on iPhone 5s with iOS 12.

                                • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                  lim Level 1 Level 1 (0 points)

                                  This issue has always been a problem with iPhone 7 with iOS 11.0 ~ 12.0. The download is complete, but the UI is not updated because the delegate is not called.

                                    • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                      eskimo Apple Staff Apple Staff (11,625 points)

                                      The download is complete, but the UI is not updated because the delegate is not called.

                                      I had a quick look at (r. 32247561) and I can’t see any indication of movement on that front.  I must stress, however, that this is just a progress issue.  You don’t need the -URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite: delegate callback for learn about requests completing.  The correct way to do that is via the -URLSession:task:didCompleteWithError: delegate callback, which, AFAIK, is functioning just fine.

                                      Earlier I suggested two potential workarounds:

                                      • Polling the countOfBytesReceived property on the task itself

                                      • Getting the NSProgress object from the task and using KVO to observe its various properties (like fractionCompleted)

                                      Various folks have tried the first and confirmed that it’s not working; I’m curious as to whether anyone has tried the second?

                                      Share and Enjoy

                                      Quinn “The Eskimo!”
                                      Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                      let myEmail = "eskimo" + "1" + "@apple.com"

                                        • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                          gebirgsbaerbel Level 1 Level 1 (0 points)

                                          I have tried to use KVO instead of polling '''countOfByesReceived''' or '''fractionCompleted''' directly. It also does not work.

                                           

                                          Also you might say this is only a progress issue, but I personally think that displaying progress for larger files is essential to having a polished and nice to use app. And downloading large files is exactly the use case, where the user will put the app to the background and periodically check for progress.

                                           

                                          Displaying download progress seems like a very basic thing and it is a bit disappointing, that there are no workarounds and no progress from Apples side on this

                                          • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                            gebirgsbaerbel Level 1 Level 1 (0 points)

                                            I have found a workaround for the issue. Once the application did return from background mode, make sure to call resume on all running tasks. This seems to reactivate callbacks to the delegate.

                                             

                                            private(set) var session: URLSession?
                                            
                                            func applicationDidBecomeActive(_ application: UIApplication) {
                                                 session?.getAllTasks(completionHandler: { tasks in
                                                      for task in tasks {
                                                           task.resume()
                                                      }
                                                 })
                                            }
                                            

                                            For me at least, this worked reliably and now I can see progress again.

                                            Would be nice to fix the issue or put this information into the documentation.

                                              • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                                eskimo Apple Staff Apple Staff (11,625 points)

                                                I have found a workaround for the issue.

                                                Your workaround worried me a little because you’re calling resume redundantly, and I wasn’t sure what impact that might have on the session.  So I discussed this issue with the NSURLSession engineering team and they suggested that the call to resume was unnecessary, and just calling getAllTasks(completionHandler:) should be sufficient to get delegate events flowing again.

                                                I did some testing of this here in my office and it seems to work, but it’s hard for me to be 100% sure because my standard background session test code was already calling getAllTasks(completionHandler:) as part of its normal operations.

                                                So, my question is: If you remove the call to resume, is your workaround still effective?

                                                Share and Enjoy

                                                Quinn “The Eskimo!”
                                                Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                                let myEmail = "eskimo" + "1" + "@apple.com"

                                                  • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                                    martt_1er Level 1 Level 1 (0 points)

                                                      Hello Eskimo

                                                     

                                                    I'm experiencing exactly the same problem as everyone in this thread.

                                                     

                                                    First I can confirm the @gebirgsbaerbel workaround DO work.

                                                    Then I tried to only call `getAllTasks(completionHandler:)`, as you suggested, but it does not work.

                                                     

                                                    I also noticed a strange thing and going to explain.

                                                     

                                                    There are 3 uses case :

                                                    1/ App is foreground during the whole download

                                                    2/ App starts the download foreground, then goes background, then completes it

                                                    3/ App starts the download foreground, then goes background, then goes foreground again, then completes it

                                                     

                                                    During 1/ here's the callbacks succession:

                                                    1• urlSession(assetDownloadTask:didFinishDownloadingTo)

                                                    2• urlSession(task:didCompleteWithError)

                                                     

                                                    During 2/ here's the callbacks

                                                    1• application(handleEventsForBackgroundURLSession:completionHandler:)

                                                    2• urlSession(assetDownloadTask:didFinishDownloadingTo)

                                                    3• urlSession(task:didCompleteWithError)

                                                    4• urlSessionDidFinishEvents(forBackgroundURLSession)

                                                     

                                                    During 3/

                                                    without using the workaround, the same callbacks as 2/

                                                    using the workaround, the same callbacks succession as 1/

                                                     

                                                    => So during 3/ the background callbacks are called, as if the application was in background.

                                                    as if the session doesn't realize the app did enter foreground before the end of the download.

                                                     

                                                    EDIT: I've done all my tests on a blank new & simple app which you can found here: http://appricot.fr/AssetDLTest.zip

                                                    If you want to reproduce the probem, you should comment the workaround, from lines 71 to 76 of ViewController.swift

                                                      • Re: NSURLSessionDownloadDelegate Methods on iPhone iOS 10.3.1
                                                        eskimo Apple Staff Apple Staff (11,625 points)

                                                        I also noticed a strange thing and going to explain.

                                                        Thanks.  Your code and detailed instructions highlighted a number of flaws in my understanding of this problem.  I’ve since corrected those and now see the behaviour you describe, that is, -getAllTasksWithCompletionHandler: is insufficient but -getAllTasksWithCompletionHandler: and -resume works.

                                                        Another interesting thing to note is that this workaround has to be done out of -applicationDidBecomeActive:.  I originally tried doing it from -applicationDidEnterBackground: and that didn’t work.

                                                        And now I’m off to determine if NSURLSession engineering is prepared to officially endorse this workaround…

                                                        Share and Enjoy

                                                        Quinn “The Eskimo!”
                                                        Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                                        let myEmail = "eskimo" + "1" + "@apple.com"