4

I have created a sample code to download a file from network repeatedly(every 30 secs or so). In iOS 7 using Background transfer services with NSURLSession
I followed this tutorial http://mobile.tutsplus.com/tutorials/iphone/ios-7-sdk-background-transfer-service/ and added a timer like this to repeat it.

    [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
mute = [NSTimer scheduledTimerWithTimeInterval:30.0f
                                        target:self
                                      selector:@selector(startDownload)
                                      userInfo:nil
                                       repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:mute forMode:NSRunLoopCommonModes];

When I run it(in background by clicking home button) in simulator and on iPad connected to the Xcode(where I can see the logs) everything works fine and it keeps downloading continuously. But when I disconnect the iPad from the Mac and run it on the iPad in background after around 3 seconds it stops running (handleEventsForBackgroundURLSession in AppDelegate get called).

In Xcode project capabilities I have selected Background fetch as Background Modes.

What am I missing here or what have I done wrong so that it gets stop after around 3 minutes? (According to the documentations with iOS 7 Background transfer services it should run continuously as there's no time limit in background for this.)

Thanks

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Madhu
  • 1,209
  • 2
  • 22
  • 28

5 Answers5

4

Background tasks in iOS7 will only give you 30 seconds at most (dramatically down from 10 minutes). You should use the new fetch background mode instead. You should not be using a timer, but use the newly provided API to ask the OS to be woken up in regular intervals and set up your download using NSURLSession.

Léo Natan
  • 56,823
  • 9
  • 150
  • 195
  • 1
    I'm already doing the download using NSURLSession and have set the Background fetch as Background Modes. I'm using Background Transfers not tasks. Can you please explain what you mean by "You should not be using a timer, but use the newly provided API to ask the OS to be woken up in regular intervals". Thanks – Madhu Dec 17 '13 at 22:58
  • @Madhu You say you are using fetch but I don't see any code related to that. It is not enough to set in background modes. You need to read on background fetch and how it works. You set a timer in the code. You shouldn't. Timer does not run once the app is suspended. – Léo Natan Dec 17 '13 at 23:50
  • Thanks for the reply. With regard to setting Background mode as Fetch, I thought all I have to do is set it in Xcode project capabilities. It seems I have misunderstood. I'll search about it and see. Thanks for the clarification. – Madhu Dec 18 '13 at 04:11
  • @Madhu Have you found a solution? If my answer has helped you, please accept. – Léo Natan Jan 30 '14 at 09:58
  • Other web pages I'm reading say iOS7 gives 3 minutes of background time? – Bradley Thomas Nov 14 '14 at 04:30
  • @Brad, to test, log the value of the available background time on UIApplication. iOS7 gives you 30 seconds. – Léo Natan Nov 14 '14 at 08:29
3

Background Fetch is something different. Background Fetch will wake up your app for periodic fetches of new data (typically, a < 30s network request looking for updates). This is not related to background NSURLSessions and should probably be turned off if you aren't actually using it for queuing NSURLSessionDownloadTasks or other update purposes.

From what I understand, it's possible that the behavior you are seeing is actually normal. I do not believe that background NSURLSessionDownloadTasks are guaranteed to run continuously or on any device configuration (AC vs battery, WiFi vs Cellular, etc.) You said that you disconnected from your Mac which would switch device state from charging to battery. Among other factors, that could be enough to pause transfers or decrease download limits. Unfortunately, this system appears to be very opaque to developers.

To be sure you are getting the highest priority available, make sure your discretionary property on your NSURLSessionConfiguration is set to false. Download tasks created while the app is in the background will always have this set to true, so just an FYI there.

Apple's sample code will put you on the right track: https://developer.apple.com/library/iOS/samplecode/SimpleBackgroundTransfer/Introduction/Intro.html

Nate T
  • 2,658
  • 1
  • 20
  • 14
2

Try the below steps. This worked fine for me.

In your .h

UIBackgroundTaskIdentifier bgTask;

In .m

//background task code
UIApplication *app = [UIApplication sharedApplication];

bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
}];

[NSTimer scheduledTimerWithTimeInterval:30.0f target:self selector:@selector(startDownload) userInfo:nil repeats:YES];

And yor method for downloading is

-(void)startDownload{

    NSLog(@"will log even if in background or foreground");
}
Nithin Michael
  • 2,166
  • 11
  • 32
  • 56
  • Thanks for the reply Nitin. But still the same result. Does your app run on iPad after disconnecting from the Mac? When run in Xcode debug mode and simulator it works. But the issue is when running it as a actual app on the iPad. – Madhu Dec 17 '13 at 21:20
  • Thanks Nitin I got it working with the help of your post and this http://stackoverflow.com/questions/10319643/objective-c-proper-use-of-beginbackgroundtaskwithexpirationhandler. But now my issue is some expert at iOS forum said that it's not a good thing to use the timer like this to run in the background. He suggested to call the starDownload when the previous download completes, without using a timer. Planning to do like that. – Madhu Dec 19 '13 at 22:34
1

Practically using [[UIApplication sharedApplication]beginBackgroundTaskWithExpirationHandler: ^{}]; will give you only 180 sec.Xcode provides the facility of background active app while debugging only just to ease developers.

Syed Ali Salman
  • 2,894
  • 4
  • 33
  • 48
0

NSURLSession download tasks are indeed not bound to time restrictions. But they are completely managed by the system. They may get postponed if the system resources are low. They are normally dialed down when there is no wifi or when the device is not plugged. The system also observes your app's use of the background transfer services and may treat it with lower priority if it detects that it abuses the feature. A background transfer every 30 seconds, is certainly considered an abuse.

I suggest dropping the use of Background Transfer Services and set up the entire thing using background fetch (which is a completely different thing btw). Just be careful if you want to reach the store, you must fall in one of the accepted uses cases for the feature to be approved for your app. If not, then there is little hope. Not sure what you are trying to do. Maybe you don't really need to have so much background activity.

Radu Simionescu
  • 4,518
  • 1
  • 35
  • 34