23

When my app is initially downloaded, the user needs to download a large file something like 200MB (upper limit). I definitely can't expect the user to keep the app open till this file is downloaded. So he/she might close the app & the app will go into background.

How can I continue to download the file in this scenario? Is this even possible in iOS?

tjpaul
  • 343
  • 3
  • 16
Srikar Appalaraju
  • 71,928
  • 54
  • 216
  • 264
  • 2
    See MMR's answer below. True background `NSURLSession` is the best way to achieve this nowadays. All of these other answers pre-date this technique. If you have a small download that needs less than 3 minutes to finish, the background task is fine approach, but for big background downloads, use background `NSURLSession`. – Rob Jul 07 '16 at 11:51

8 Answers8

41

Add below in your - (void)applicationDidEnterBackground:(UIApplication *)application

UIApplication  *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask;

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

and you are good to go... I have this in one of my published download manager app

This will work just fine. You can also check how much time you have, since apple only enable 10 minutes background tasks. Use:

NSTimeInterval ti = [[UIApplication sharedApplication]backgroundTimeRemaining];
NSLog(@"backgroundTimeRemaining: %f", ti); // just for debug
Ricardo Rivaldo
  • 1,687
  • 2
  • 15
  • 13
Saurabh
  • 22,743
  • 12
  • 84
  • 133
  • So with this I can download? Is there any time limit like @nick says above? – Srikar Appalaraju Jan 14 '12 at 14:40
  • 10
    yes.. apple talks about time limit.. but I can download a file with size of 800 mb with above code.. and the app is in app store.. – Saurabh Jan 14 '12 at 14:59
  • wow!! that comment of yours is precious info @Saurabh. Thanks!! – Saurabh Passolia Jan 14 '12 at 16:08
  • 1
    @samfisher - if you think my comment has precious info.. then why not click on the upvote link and give me some reputation.. :) :) – Saurabh Jan 14 '12 at 17:09
  • @Saurabh, i would have up-voted after verifying your words through it if you would have mentioned the app's name. :) – Saurabh Passolia Jan 14 '12 at 18:09
  • 11
    If the app takes more than 10 minutes in the background iOS will terminate your app. So if the users network is slow it won't work properly. – Tony Million Jan 16 '12 at 20:20
  • if your app specifies some background mode and actualy uses it (gps-> actualy use location services, audio -> play music, etc); you can request the background task as many times as you want, just be carefull to close the previous one when it expires. Also, expect to be suspended if you end the background mode specific processing. – Mihai Timar Apr 18 '12 at 11:54
  • I have used above code, but till downloading is automatically stop after some time when app in background mode. :( please guide me. – Pravin Tate Jul 02 '15 at 06:04
  • @PravinTate - I posted this answer on "Jan 14 '12" things might have changed in 2015.. didn't get time to check it with iOS 8. Please do research and udpate answer – Saurabh Jul 03 '15 at 14:53
  • @saurabh I have implement that solution but its just useful for cancell downloading and I get control before its stop downloading but I can't restart it.I'm stuck about how can I resume current downloading – Pravin Tate Jul 03 '15 at 17:00
7

You could use NSURLSession introduced in iOS 7.0 and later to continue the uploading/download of an file even when the app is suspended.

Apple documentation

The NSURLSession class and related classes provide an API for downloading content. This API provides a rich set of delegate methods for supporting authentication and gives your app the ability to perform background downloads when your app is not running or, in iOS, while your app is suspended.

And

Background sessions let you perform uploads and downloads of content in the background while your app is not running. You can create a background session configuration by calling the backgroundSessionConfiguration: method on the NSURLSessionConfiguration class.

A cool tutorial to use NSURLSession at this link.

Marimuthu
  • 437
  • 4
  • 14
  • 1
    This is the correct answer. Use background `NSURLSession`! The other answers pre-date this technique, but this is now the best way to accomplish long downloads that might exceed the 3 minutes allowed by `UIBackgroundTask` approach. – Rob Jul 07 '16 at 11:41
7

It is possible to start a background task when you begin the download:

Apps that are transitioning to the background can request an extra amount of time to finish any important last-minute tasks.

Executing a Finite-Length Task in the Background

However, such a task is limited to an undefined amount of execution time by the system. However, a 200Mb file download may be too large a task in this case.

Crazyrems
  • 2,551
  • 22
  • 40
Chris Gummer
  • 4,772
  • 1
  • 24
  • 17
  • Yes. You might want to look at using a network library that allows you to pause and resume downloads from where they left off, so the user doesn't have to start again from scratch if the download is interrupted. ASIHttpRequest can do this, but it's not supported any more since it doesn't work with ARC. – Nick Lockwood Jan 14 '12 at 11:47
  • 2
    thats not correct anymore. On ARC for ASIHttp, you can use a static library compiled with non ARC environment. – Saurabh Passolia Apr 12 '13 at 05:21
5

In one of my apps, I was loading huge amount of data. I definitely can't expect the user to keep the app in foreground until the data is downloaded. I just use following code to get the data downloading while app is in background. Its working properly :-)
Please go through following steps:

1) use following line in header file of ViewController

   @property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;

synthesis it in .m file.

2) in ViewDidLoad assign UIBackgroundTaskIdentifier like:

   self.backgroundTask = UIBackgroundTaskInvalid;

3) Use following line of code, here I am just keeping on getDataFromServer method inside beginBackgroundTaskWithExpirationHandler: block.

        self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{

        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
        self.backgroundTask = UIBackgroundTaskInvalid;
    }];

    /* Here your downloading Code, let say getDataFromServer method */

    [self getDataFromServer]; // Its dummy method

    /* Your downloading Code End Here */

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
        self.backgroundTask = UIBackgroundTaskInvalid;
    });

4) If you want to check time remaining to download data in background, include following line in applicationDidEnterBackground:(UIApplication *)application delegate method of AppDelegate:

      NSLog(@"Background time remaining = %.1f seconds", [UIApplication sharedApplication].backgroundTimeRemaining);
nathanchere
  • 8,008
  • 15
  • 65
  • 86
Himanshu Mahajan
  • 4,779
  • 2
  • 36
  • 29
3

AFNetworking allows you to perform heavy operation in background.

AFNetworking Library is a excellent combination of NSURLConnection and NSOperationQueue.This library is used for Asynchronous downloading in the background not affecting the other application.

AFNetworking allows you to handle the downloading with ExpirationHandle i.e. if anyhow during the downloading the connection is lost , it will again connect to it.

Library Source for AFNetworking

Reference Source AFNetworking works in Background

Apple Reference Link Apple

Background Execution and Multitasking Apple

Community
  • 1
  • 1
Sumit Sharma
  • 1,847
  • 1
  • 22
  • 25
0
#pragma mark - View Loading handling
- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
}

#pragma mark - Background handling when application goes background
UIBackgroundTaskIdentifier background_task;
- (void)appDidEnterBackground:(NSNotification *)notification {
    UIApplication  *application = [UIApplication sharedApplication];
    if([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)])
    {
        NSLog(@"Multitasking Supported");
        if (background_task == UIBackgroundTaskInvalid) {
            background_task = [application beginBackgroundTaskWithExpirationHandler:^ {
                NSLog(@"Background task expiration\n");
                //Clean up code. Tell the system that we are done.
                [application endBackgroundTask: background_task];
                background_task = UIBackgroundTaskInvalid;
            }];
            //To make the code block asynchronous
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                //### background task starts
                NSLog(@"Running in the background\n");
                for(int cnt=0; cnt<10; cnt++) //while(TRUE)
                {
                    NSLog(@"Background time Remaining: %f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
                    [NSThread sleepForTimeInterval:1]; //wait for 1 sec
                }
                //#### background task ends
                //Clean up code. Tell the system that we are done.
                NSLog(@"here you can do something before it really enters background");
                [NSThread sleepForTimeInterval:1]; //wait for 1 sec
                [application endBackgroundTask: background_task];
                background_task = UIBackgroundTaskInvalid;
            });
        }
        else
        {
            NSLog(@"Multitasking Not Supported");
        }
    }
}

You can know more from this slide.
I just do some simple useful modification from the snippet of this slide. Hope this helps.

srjohnhuang
  • 232
  • 5
  • 18
0

Build a newsStand iOS application; not a standart iOS application.

Standart iOS aplications:

  • can not download data when closed.
  • can download data in limited time when pushed to background.
  • Not enough time to download 200mb.

NewsStand applications have an extra time privilege to download when closed or inBackground. Once in every 24 hours, they have a privilege to answer a remoteContentReady delegate call.

Building a newsStand application is no different than building a standart iOS application. You will just mark it as newStand application.

Then you will have privilege to run code which is inside remoteContentReady delegation.

To receive remoteContentReady signal, you have to send a signal from your serverside (c#, php, bla bla).

Not to every single iOS app. Something like a remoteNotification signal. You may need ssl certification for your website in order to accomplish this.

Best Regards

Add080bbA
  • 1,818
  • 1
  • 18
  • 25
0

Unfortunately most answers here are outdated in 2020! iOS 13 reduces the time of -beginBackgroundTaskWithExpirationHandler: to seconds from minutes and also kills the app with adverse effects. I also consider disabling auto screensaver mode for the duration of the download. More information can be found here:

cat
  • 2,871
  • 1
  • 23
  • 28